Esempio n. 1
0
int ServerApplication::init(int argc, char *argv[]) {
  // Hide child's output
  if (hasFeature(FEATURE_SERVER) && options["child"].toBoolean())
    options["log-to-screen"].setDefault(false);

  int ret = Application::init(argc, argv);
  if (ret == -1) return -1;

  if (!hasFeature(FEATURE_SERVER)) return ret;

  if (!options["child"].toBoolean()) {
#ifndef _WIN32
    if (options["fork"].toBoolean()) {
      // Note, all threads must be stopped before daemonize() forks and
      // SignalManager runs in a thread.
      SignalManager::instance().setEnabled(false);
      SystemUtilities::daemonize();
      SignalManager::instance().setEnabled(true);
    }
#endif

    if (options["pid"].toBoolean()) {
      // Try to acquire an exclusive lock
      new ProcessLock(options["pid-file"], 10); // OK to leak
      LOG_INFO(1, "Acquired exclusive lock on " << options["pid-file"]);
    }
  }

#ifndef _WIN32
  try {
    if (options["run-as"].hasValue()) {
      LOG_INFO(1, "Switching to user " << options["run-as"]);
      SystemUtilities::setUser(options["run-as"]);
    }
  } CBANG_CATCH_ERROR;
#endif

  if (!options["child"].toBoolean() && options["respawn"].toBoolean()) {
#ifndef _WIN32
    // Child restart handler
    SignalManager::instance().addHandler(SIGUSR1, this);
#endif

    // Setup child arguments
    vector<string> args;
    args.push_back(argv[0]);
    args.push_back((char *)"--child");
    args.push_back((char *)"--lifeline");
    args.push_back(String(SystemUtilities::getPID()));
    args.insert(args.end(), argv + 1, argv + argc);

    unsigned lastRespawn = 0;
    unsigned respawnCount = 0;

    while (!shouldQuit()) {
      // Check respawn rate
      unsigned now = Time::now();
      if (now - lastRespawn < 60) {
        if (++respawnCount == 5) {
          LOG_ERROR("Respawning too fast. Exiting.");
          break;
        }
      } else respawnCount = 0;
      lastRespawn = now;

      // Spawn child
      Subprocess child;
      child.exec(args, Subprocess::NULL_STDOUT | Subprocess::NULL_STDERR);

      uint64_t killTime = 0;
      while (child.isRunning()) {
        if (!killTime && (restartChild || shouldQuit())) {
          LOG_INFO(1, "Shutting down child at PID=" << child.getPID());

          child.interrupt();
          restartChild = false;
          killTime = Time::now() + 300; // Give it 5 mins to shutdown
        }

        if (killTime && killTime < Time::now()) {
          LOG_INFO(1, "Child failed to shutdown cleanly, killing");

          killTime = 0;
          child.kill();
        }

        Timer::sleep(0.1);
      }

      LOG_INFO(1, "Child exited with return code " << child.getReturnCode());
    }

    exit(0);
  }

  return ret;
}