diff --git a/gennghttpxfun.py b/gennghttpxfun.py index a38fbca1..2aa76ad3 100755 --- a/gennghttpxfun.py +++ b/gennghttpxfun.py @@ -195,6 +195,7 @@ OPTIONS = [ "frontend-quic-server-id", "frontend-quic-secret-file", "rlimit-memlock", + "max-worker-processes", ] LOGVARS = [ diff --git a/src/shrpx.cc b/src/shrpx.cc index 824eb739..80ee1d32 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -300,6 +300,17 @@ void worker_process_remove(const WorkerProcess *wp) { } } // namespace +namespace { +void worker_process_adjust_limit() { + auto config = get_config(); + + if (config->max_worker_processes && + worker_processes.size() > config->max_worker_processes) { + worker_processes.pop_front(); + } +} +} // namespace + namespace { void worker_process_remove_all() { std::deque>().swap(worker_processes); @@ -3201,6 +3212,19 @@ Process: process. nghttpx still spawns additional process if neverbleed is used. In the single process mode, the signal handling feature is disabled. + --max-worker-processes= + The maximum number of worker processes. nghttpx spawns + new worker process when it reloads its configuration. + The previous worker process enters graceful termination + period and will terminate when it finishes handling the + existing connections. However, if reloading + configurations happen very frequently, the worker + processes might be piled up if they take a bit long time + to finish the existing connections. With this option, + if the number of worker processes exceeds the given + value, the oldest worker process is terminated + immediately. Specifying 0 means no limit and it is the + default behaviour. Scripting: --mruby-file= @@ -3773,6 +3797,8 @@ void reload_config(WorkerProcess *wp) { ipc_send(last_wp.get(), SHRPX_IPC_UNLOAD_BPF_OBJECT); #endif // ENABLE_HTTP3 + worker_process_adjust_limit(); + if (!get_config()->pid_file.empty()) { save_pid(); } @@ -4101,6 +4127,7 @@ int main(int argc, char **argv) { {SHRPX_OPT_FRONTEND_QUIC_SECRET_FILE.c_str(), required_argument, &flag, 186}, {SHRPX_OPT_RLIMIT_MEMLOCK.c_str(), required_argument, &flag, 187}, + {SHRPX_OPT_MAX_WORKER_PROCESSES.c_str(), required_argument, &flag, 188}, {nullptr, 0, nullptr, 0}}; int option_index = 0; @@ -4992,6 +5019,10 @@ int main(int argc, char **argv) { // --rlimit-memlock cmdcfgs.emplace_back(SHRPX_OPT_RLIMIT_MEMLOCK, StringRef{optarg}); break; + case 188: + // --max-worker-processes + cmdcfgs.emplace_back(SHRPX_OPT_MAX_WORKER_PROCESSES, StringRef{optarg}); + break; default: break; } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index a5689219..f4a6e67a 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -2248,6 +2248,9 @@ int option_lookup_token(const char *name, size_t namelen) { } break; case 's': + if (util::strieq_l("max-worker-processe", name, 19)) { + return SHRPX_OPTID_MAX_WORKER_PROCESSES; + } if (util::strieq_l("tls13-client-cipher", name, 19)) { return SHRPX_OPTID_TLS13_CLIENT_CIPHERS; } @@ -4139,6 +4142,8 @@ int parse_config(Config *config, int optid, const StringRef &opt, return 0; } + case SHRPX_OPTID_MAX_WORKER_PROCESSES: + return parse_uint(&config->max_worker_processes, opt, optarg); case SHRPX_OPTID_CONF: LOG(WARN) << "conf: ignored"; diff --git a/src/shrpx_config.h b/src/shrpx_config.h index d9c6fcef..b70c9457 100644 --- a/src/shrpx_config.h +++ b/src/shrpx_config.h @@ -396,6 +396,8 @@ constexpr auto SHRPX_OPT_FRONTEND_QUIC_SERVER_ID = constexpr auto SHRPX_OPT_FRONTEND_QUIC_SECRET_FILE = StringRef::from_lit("frontend-quic-secret-file"); constexpr auto SHRPX_OPT_RLIMIT_MEMLOCK = StringRef::from_lit("rlimit-memlock"); +constexpr auto SHRPX_OPT_MAX_WORKER_PROCESSES = + StringRef::from_lit("max-worker-processes"); constexpr size_t SHRPX_OBFUSCATED_NODE_LENGTH = 8; @@ -1075,7 +1077,8 @@ struct Config { single_process{false}, single_thread{false}, ignore_per_pattern_mruby_error{false}, - ev_loop_flags{0} { + ev_loop_flags{0}, + max_worker_processes{0} { } ~Config(); @@ -1129,6 +1132,7 @@ struct Config { bool ignore_per_pattern_mruby_error; // flags passed to ev_default_loop() and ev_loop_new() int ev_loop_flags; + size_t max_worker_processes; }; const Config *get_config(); @@ -1255,6 +1259,7 @@ enum { SHRPX_OPTID_MAX_HEADER_FIELDS, SHRPX_OPTID_MAX_REQUEST_HEADER_FIELDS, SHRPX_OPTID_MAX_RESPONSE_HEADER_FIELDS, + SHRPX_OPTID_MAX_WORKER_PROCESSES, SHRPX_OPTID_MRUBY_FILE, SHRPX_OPTID_NO_ADD_X_FORWARDED_PROTO, SHRPX_OPTID_NO_HOST_REWRITE,