Skip to content

Commit

Permalink
Merge pull request #336 from mmd-osm/patch/nodaemon
Browse files Browse the repository at this point in the history
Daemon mode
  • Loading branch information
mmd-osm authored Dec 9, 2023
2 parents 610d668 + f9e3a8c commit 67b0f0c
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 108 deletions.
9 changes: 5 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
12 changes: 7 additions & 5 deletions Dockerfile2204
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

9 changes: 5 additions & 4 deletions Dockerfile_bookworm
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
9 changes: 5 additions & 4 deletions Dockerfile_trixie
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
204 changes: 113 additions & 91 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ static void get_options(int argc, char **argv, po::variables_map &options) {
("maxdebt", po::value<long>(), "maximum debt (in Mb) to allow each client before rate limiting")
("moderator-maxdebt", po::value<long>(), "maximum debt (in Mb) to allow each moderator before rate limiting")
("port", po::value<int>(), "FCGI port number (e.g. 8000) to listen on. This option is for backwards compatibility, please use --socket for new configurations.")
("socket", po::value<string>(), "FCGI port number (e.g. :8000) or UNIX socket to listen on")
("socket", po::value<string>(), "FCGI port number (e.g. :8000, or 127.0.0.1:8000) or UNIX domain socket to listen on")
("configfile", po::value<string>(), "Config file")
;
// clang-format on
Expand Down Expand Up @@ -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<int>();
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<pid_t> children;

// set global_settings based on provided options
global_settings::set_configuration(std::make_unique<global_settings_via_options>(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<string>(), 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<int>());
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<string>().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<int>();
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<pid_t> 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<string>().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<string>().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<string>().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<string>().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<string>(), 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<int>());
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<string>().c_str());
}
} else {
// record our pid if requested
if (options.count("pidfile")) {
std::ofstream pidfile(options["pidfile"].as<string>().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<string>().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<global_settings_via_options>(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;
Expand Down

0 comments on commit 67b0f0c

Please sign in to comment.