From 3834c35a22d1bb0f5f89d4b5c2c73600c143e15c Mon Sep 17 00:00:00 2001 From: mmd-osm Date: Sat, 9 Dec 2023 00:16:12 +0100 Subject: [PATCH 1/2] Show warning when providing --instances param in non-daemon mode Some refactoring into non-daemon/daemon mode Fixes #330 --- src/main.cpp | 204 ++++++++++++++++++++++++++++----------------------- 1 file changed, 113 insertions(+), 91 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a5d8de27..af978cd4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -99,7 +99,7 @@ static void get_options(int argc, char **argv, po::variables_map &options) { ("maxdebt", po::value(), "maximum debt (in Mb) to allow each client before rate limiting") ("moderator-maxdebt", po::value(), "maximum debt (in Mb) to allow each moderator before rate limiting") ("port", po::value(), "FCGI port number (e.g. 8000) to listen on. This option is for backwards compatibility, please use --socket for new configurations.") - ("socket", po::value(), "FCGI port number (e.g. :8000) or UNIX socket to listen on") + ("socket", po::value(), "FCGI port number (e.g. :8000, or 127.0.0.1:8000) or UNIX domain socket to listen on") ("configfile", po::value(), "Config file") ; // clang-format on @@ -290,116 +290,138 @@ void setup_backends() { register_backend(make_staticxml_backend()); } -int main(int argc, char **argv) { - try { - po::variables_map options; - int socket; - // set up all the backends - setup_backends(); +void daemon_mode(const po::variables_map &options, int socket) +{ + size_t instances = 0; + { + int opt_instances = options["instances"].as(); + if (opt_instances > 0) { + instances = opt_instances; + } else { + throw std::runtime_error( + "Number of instances must be strictly positive."); + } + } - // get options - get_options(argc, argv, options); + bool children_terminated = false; + std::set children; - // set global_settings based on provided options - global_settings::set_configuration(std::make_unique(options)); + // make ourselves into a daemon + daemonise(); - // get the socket to use - if (options.count("socket")) { - if ((socket = fcgi_request::open_socket(options["socket"].as(), 5)) < 0) { - throw runtime_error("Couldn't open FCGX socket."); - } - // fall back to the old --port option if socket isn't available. - } else if (options.count("port")) { - auto sock_str = fmt::format(":{:d}", options["port"].as()); - if ((socket = fcgi_request::open_socket(sock_str, 5)) < 0) { - throw runtime_error("Couldn't open FCGX socket (from port)."); + // record our pid if requested + if (options.count("pidfile")) { + std::ofstream pidfile(options["pidfile"].as().c_str()); + pidfile << getpid() << std::endl; + } + + // loop until we have been asked to stop and have no more children + while (!terminate_requested || children.size() > 0) { + pid_t pid; + + // start more children if we don't have enough + while (!terminate_requested && (children.size() < instances)) { + if ((pid = fork()) < 0) { + throw runtime_error("fork failed."); + } else if (pid == 0) { + process_requests(socket, options); + exit(0); } - } else { - socket = 0; + + children.insert(pid); } - // are we supposed to run as a daemon? - if (options.count("daemon")) { - size_t instances = 0; - { - int opt_instances = options["instances"].as(); - if (opt_instances > 0) { - instances = opt_instances; - } else { - throw std::runtime_error( - "Number of instances must be strictly positive."); - } - } + // wait for a child to exit + if ((pid = wait(NULL)) >= 0) { + children.erase(pid); + } else if (errno != EINTR) { + throw runtime_error("wait failed."); + } - bool children_terminated = false; - std::set children; + // pass on any termination request to our children + if (terminate_requested && !children_terminated) { + for (auto pid : children) { kill(pid, SIGTERM); } - // make ourselves into a daemon - daemonise(); + children_terminated = true; + } - // record our pid if requested - if (options.count("pidfile")) { - std::ofstream pidfile(options["pidfile"].as().c_str()); - pidfile << getpid() << std::endl; - } + // pass on any reload request to our children + if (reload_requested) { + for (auto pid : children) { kill(pid, SIGHUP); } - // loop until we have been asked to stop and have no more children - while (!terminate_requested || children.size() > 0) { - pid_t pid; - - // start more children if we don't have enough - while (!terminate_requested && (children.size() < instances)) { - if ((pid = fork()) < 0) { - throw runtime_error("fork failed."); - } else if (pid == 0) { - process_requests(socket, options); - exit(0); - } + reload_requested = false; + } + } + + // remove any pid file + if (options.count("pidfile")) { + remove(options["pidfile"].as().c_str()); + } +} - children.insert(pid); - } +void non_daemon_mode(const po::variables_map &options, int socket) +{ + if (options.count("instances")) { + std::cerr << "[WARN] The --instances parameter is ignored in non-daemon mode, running as single process only.\n" + "[WARN] If the process terminates, it must be restarted externally.\n"; + } - // wait for a child to exit - if ((pid = wait(NULL)) >= 0) { - children.erase(pid); - } else if (errno != EINTR) { - throw runtime_error("wait failed."); - } + // record our pid if requested + if (options.count("pidfile")) { + std::ofstream pidfile(options["pidfile"].as().c_str()); + pidfile << getpid() << std::endl; + } - // pass on any termination request to our children - if (terminate_requested && !children_terminated) { - for (auto pid : children) { kill(pid, SIGTERM); } + // do work here + process_requests(socket, options); - children_terminated = true; - } + // remove any pid file + if (options.count("pidfile")) { + remove(options["pidfile"].as().c_str()); + } +} - // pass on any reload request to our children - if (reload_requested) { - for (auto pid : children) { kill(pid, SIGHUP); } +int init_socket(const po::variables_map &options) +{ + int socket = 0; - reload_requested = false; - } - } + if (options.count("socket")) { + if ((socket = fcgi_request::open_socket(options["socket"].as(), 5)) < 0) { + throw runtime_error("Couldn't open FCGX socket."); + } + // fall back to the old --port option if socket isn't available. + } else if (options.count("port")) { + auto sock_str = fmt::format(":{:d}", options["port"].as()); + if ((socket = fcgi_request::open_socket(sock_str, 5)) < 0) { + throw runtime_error("Couldn't open FCGX socket (from port)."); + } + } + return socket; +} - // remove any pid file - if (options.count("pidfile")) { - remove(options["pidfile"].as().c_str()); - } - } else { - // record our pid if requested - if (options.count("pidfile")) { - std::ofstream pidfile(options["pidfile"].as().c_str()); - pidfile << getpid() << std::endl; - } - // do work here - process_requests(socket, options); +int main(int argc, char **argv) { + try { + po::variables_map options; - // remove any pid file - if (options.count("pidfile")) { - remove(options["pidfile"].as().c_str()); - } + // set up all the backends + setup_backends(); + + // get options + get_options(argc, argv, options); + + // set global_settings based on provided options + global_settings::set_configuration(std::make_unique(options)); + + // get the socket to use + auto socket = init_socket(options); + + // are we supposed to run as a daemon? + if (options.count("daemon")) { + daemon_mode(options, socket); + } else { + non_daemon_mode(options, socket); } } catch (const po::error & e) { std::cerr << "Error: " << e.what() << "\n(\"openstreetmap-cgimap --help\" for help)" << std::endl; From f9e3a8ccf07eb41060d44963e69b2da900f3f8fd Mon Sep 17 00:00:00 2001 From: mmd-osm Date: Sat, 9 Dec 2023 15:32:17 +0100 Subject: [PATCH 2/2] Docker: run cgimap in daemon mode, redirect logfile to daemon stdout --- Dockerfile | 9 +++++---- Dockerfile2204 | 12 +++++++----- Dockerfile_bookworm | 9 +++++---- Dockerfile_trixie | 9 +++++---- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Dockerfile b/Dockerfile index c5bdd0fa..9c180eaf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,7 +22,7 @@ COPY . ./ # Compile, install and remove source RUN ./autogen.sh && \ ./configure --enable-static --disable-shared --enable-yajl && \ - make -j3 && \ + make -j${nproc} check TESTS= && \ make check || ( cat ./test-suite.log ; exit 1 ) && \ strip openstreetmap-cgimap @@ -47,14 +47,15 @@ ENV CGIMAP_HOST db ENV CGIMAP_DBNAME openstreetmap ENV CGIMAP_USERNAME openstreetmap ENV CGIMAP_PASSWORD openstreetmap -ENV CGIMAP_PIDFILE /dev/null -ENV CGIMAP_LOGFILE /dev/stdout ENV CGIMAP_MEMCACHE memcached ENV CGIMAP_RATELIMIT 204800 ENV CGIMAP_MAXDEBT 250 ENV CGIMAP_MODERATOR_RATELIMIT 1048576 ENV CGIMAP_MODERATOR_MAXDEBT 1024 +ENV CGIMAP_PORT 8000 +ENV CGIMAP_INSTANCES 10 EXPOSE 8000 -CMD ["/usr/local/bin/openstreetmap-cgimap", "--port=8000", "--instances=30"] +ENTRYPOINT /usr/local/bin/openstreetmap-cgimap --pidfile /tmp/cgimap.pid --logfile=/proc/1/fd/1 --daemon && \ + tail --pid=$(cat /tmp/cgimap.pid) -f /dev/null diff --git a/Dockerfile2204 b/Dockerfile2204 index 155874f0..39d6e256 100644 --- a/Dockerfile2204 +++ b/Dockerfile2204 @@ -21,8 +21,8 @@ COPY . ./ # Compile, install and remove source RUN ./autogen.sh && \ ./configure --enable-static --disable-shared --enable-yajl CXXFLAGS="-Wall -Wextra -Wpedantic -Wno-unused-parameter" && \ - make -j3 && \ - make check && \ + make -j${nproc} check TESTS= && \ + make check || ( cat ./test-suite.log ; exit 1 ) && \ strip openstreetmap-cgimap FROM ubuntu:22.04 @@ -46,14 +46,16 @@ ENV CGIMAP_HOST db ENV CGIMAP_DBNAME openstreetmap ENV CGIMAP_USERNAME openstreetmap ENV CGIMAP_PASSWORD openstreetmap -ENV CGIMAP_PIDFILE /dev/null -ENV CGIMAP_LOGFILE /dev/stdout ENV CGIMAP_MEMCACHE memcached ENV CGIMAP_RATELIMIT 204800 ENV CGIMAP_MAXDEBT 250 ENV CGIMAP_MODERATOR_RATELIMIT 1048576 ENV CGIMAP_MODERATOR_MAXDEBT 1024 +ENV CGIMAP_PORT 8000 +ENV CGIMAP_INSTANCES 10 EXPOSE 8000 -CMD ["/usr/local/bin/openstreetmap-cgimap", "--port=8000", "--instances=30"] +ENTRYPOINT /usr/local/bin/openstreetmap-cgimap --pidfile /tmp/cgimap.pid --logfile=/proc/1/fd/1 --daemon && \ + tail --pid=$(cat /tmp/cgimap.pid) -f /dev/null + diff --git a/Dockerfile_bookworm b/Dockerfile_bookworm index 4aeb2249..7b4f5c19 100644 --- a/Dockerfile_bookworm +++ b/Dockerfile_bookworm @@ -21,7 +21,7 @@ COPY . ./ # Compile, install and remove source RUN ./autogen.sh && \ ./configure --enable-static --disable-shared --enable-yajl CXXFLAGS="-Wall -Wextra -Wpedantic -Wno-unused-parameter" && \ - make -j3 check TESTS= && \ + make -j${nproc} check TESTS= && \ make check || ( cat ./test-suite.log ; exit 1 ) && \ strip openstreetmap-cgimap @@ -46,14 +46,15 @@ ENV CGIMAP_HOST db ENV CGIMAP_DBNAME openstreetmap ENV CGIMAP_USERNAME openstreetmap ENV CGIMAP_PASSWORD openstreetmap -ENV CGIMAP_PIDFILE /dev/null -ENV CGIMAP_LOGFILE /dev/stdout ENV CGIMAP_MEMCACHE memcached ENV CGIMAP_RATELIMIT 204800 ENV CGIMAP_MAXDEBT 250 ENV CGIMAP_MODERATOR_RATELIMIT 1048576 ENV CGIMAP_MODERATOR_MAXDEBT 1024 +ENV CGIMAP_PORT 8000 +ENV CGIMAP_INSTANCES 10 EXPOSE 8000 -CMD ["/usr/local/bin/openstreetmap-cgimap", "--port=8000", "--instances=30"] +ENTRYPOINT /usr/local/bin/openstreetmap-cgimap --pidfile /tmp/cgimap.pid --logfile=/proc/1/fd/1 --daemon && \ + tail --pid=$(cat /tmp/cgimap.pid) -f /dev/null diff --git a/Dockerfile_trixie b/Dockerfile_trixie index 4e8386cd..5c7d3d9e 100644 --- a/Dockerfile_trixie +++ b/Dockerfile_trixie @@ -21,7 +21,7 @@ COPY . ./ # Compile, install and remove source RUN ./autogen.sh && \ ./configure --enable-static --disable-shared --enable-yajl CXXFLAGS="-Wall -Wextra -Wpedantic -Wno-unused-parameter" && \ - make -j3 check TESTS= && \ + make -j${nproc} check TESTS= && \ make check || ( cat ./test-suite.log ; exit 1 ) && \ strip openstreetmap-cgimap @@ -46,14 +46,15 @@ ENV CGIMAP_HOST db ENV CGIMAP_DBNAME openstreetmap ENV CGIMAP_USERNAME openstreetmap ENV CGIMAP_PASSWORD openstreetmap -ENV CGIMAP_PIDFILE /dev/null -ENV CGIMAP_LOGFILE /dev/stdout ENV CGIMAP_MEMCACHE memcached ENV CGIMAP_RATELIMIT 204800 ENV CGIMAP_MAXDEBT 250 ENV CGIMAP_MODERATOR_RATELIMIT 1048576 ENV CGIMAP_MODERATOR_MAXDEBT 1024 +ENV CGIMAP_PORT 8000 +ENV CGIMAP_INSTANCES 10 EXPOSE 8000 -CMD ["/usr/local/bin/openstreetmap-cgimap", "--port=8000", "--instances=30"] +ENTRYPOINT /usr/local/bin/openstreetmap-cgimap --pidfile /tmp/cgimap.pid --logfile=/proc/1/fd/1 --daemon && \ + tail --pid=$(cat /tmp/cgimap.pid) -f /dev/null