class ProcessService extends StatefulService {

    protected void startProcess(Operation op, ProcessState state) {
        if (this.stopProcess()) {
            // Reset back-off if the process was alive longer than STABLE_THRESHOLD_MILLIS.
            // This threshold determines when we no longer see a process as flapping.
            if ((this.processStopTimeMillis - this.processStartTimeMillis) >= STABLE_THRESHOLD_MILLIS) {
                this.startDelayExp = 0;
            }

            this.startDelayMillis = TimeUnit.SECONDS
                    .toMillis((int) Math.pow(2, this.startDelayExp) - 1);
            if (this.startDelayMillis < MAX_START_DELAY_MILLIS) {
                this.startDelayExp++;
            } else {
                this.startDelayMillis = MAX_START_DELAY_MILLIS;
            }

            // print the log before restarting
            if (state.logLink != null && !state.logLink.isEmpty()) {
                Operation getLog = Operation.createGet(UriUtils.buildUri(this.getHost(),
                        state.logLink, "lineCount=" + LINES))
                        .setCompletion((o, e) -> {
                            if (e != null) {
                                logWarning("Unable to get logs: %s", e.getMessage());
                                return;
                            }
                            String json = Utils.toJsonHtml(o.getBodyRaw());
                            logInfo("%s", json);
                        });
                sendRequest(getLog);
            }

            setStat(STAT_NAME_START_DELAY_MILLIS, this.startDelayMillis);
            logWarning("Process %s exited with status %d, restarting in %ds",
                    state.arguments[0],
                    this.processExitStatus,
                    TimeUnit.MILLISECONDS.toSeconds(this.startDelayMillis));
        }

        // Check if we need to wait longer before starting the process again.
        if ((new Date()).getTime() < this.processStopTimeMillis + this.startDelayMillis) {
            op.complete();
            return;
        }

        logInfo("Starting %s", state.arguments[0]);
        adjustStat(STAT_NAME_START_COUNT, 1);

        ProcessBuilder pb = new ProcessBuilder(state.arguments);
        if (state.logFile != null) {
            File file = new File(state.logFile);
            pb.redirectErrorStream(true);
            pb.redirectOutput(Redirect.appendTo(file));
        }

        try {
            this.process = pb.start();
            this.processStartTimeMillis = (new Date()).getTime();
        } catch (Exception e) {
            logWarning("Failure starting %s (%s)",
                    state.arguments[0],
                    e.toString());
            op.fail(e);
            return;
        }

        op.complete();
    }

    public  ProcessService();

}