diff options
author | Christian Grothoff <christian@grothoff.org> | 2021-12-02 08:02:20 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2021-12-02 08:02:20 +0100 |
commit | 5a7dd001250da73ce2236f245b6bba9a1663477e (patch) | |
tree | e3e45fcc971fb084fb274443c87984f38e398dd6 /src/exchange/taler-exchange-httpd.c | |
parent | e8fc5d8d5c5eb07c9b6be41fd9bab0552a6ac672 (diff) |
improve suicide logic
Diffstat (limited to 'src/exchange/taler-exchange-httpd.c')
-rw-r--r-- | src/exchange/taler-exchange-httpd.c | 148 |
1 files changed, 101 insertions, 47 deletions
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c index 64304e9c..327bcd1e 100644 --- a/src/exchange/taler-exchange-httpd.c +++ b/src/exchange/taler-exchange-httpd.c @@ -77,6 +77,11 @@ static int allow_address_reuse; const struct GNUNET_CONFIGURATION_Handle *TEH_cfg; /** + * Handle to the HTTP server. + */ +static struct MHD_Daemon *mhd; + +/** * Our KYC configuration. */ struct TEH_KycOptions TEH_kyc_config; @@ -123,6 +128,12 @@ static unsigned int connection_timeout = 30; static int connection_close; /** + * True if we should commit suicide once all active + * connections are finished. + */ +bool TEH_suicide; + +/** * Value to return from main() */ static int global_ret; @@ -138,6 +149,11 @@ static uint16_t serve_port; static unsigned long long req_count; /** + * Counter for the number of open connections. + */ +static unsigned long long active_connections; + +/** * Limit for the number of requests this HTTP may process before restarting. * (This was added as one way of dealing with unavoidable memory fragmentation * happening slowly over time.) @@ -263,6 +279,45 @@ handle_post_coins (struct TEH_RequestContext *rc, /** + * Increments our request counter and checks if this + * process should commit suicide. + */ +static void +check_suicide (void) +{ + int fd; + pid_t chld; + unsigned long long cnt; + + cnt = req_count++; + if (req_max != cnt) + return; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Restarting exchange service after %llu requests\n", + cnt); + /* Stop accepting new connections */ + fd = MHD_quiesce_daemon (mhd); + GNUNET_break (0 == close (fd)); + /* Continue handling existing connections in child, + so that this process can die and be replaced by + systemd with a fresh one */ + chld = fork (); + if (-1 == chld) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "fork"); + _exit (1); + } + if (0 != chld) + { + /* We are the parent, instant-suicide! */ + _exit (0); + } + TEH_suicide = true; +} + + +/** * Function called whenever MHD is done with a request. If the * request was a POST, we may have stored a `struct Buffer *` in the * @a con_cls that might still need to be cleaned up. Call the @@ -290,6 +345,7 @@ handle_mhd_completion_callback (void *cls, return; GNUNET_async_scope_enter (&rc->async_scope_id, &old_scope); + check_suicide (); TEH_check_invariants (); if (NULL != rc->rh_cleaner) rc->rh_cleaner (rc); @@ -1642,8 +1698,19 @@ connection_done (void *cls, (void) cls; (void) connection; (void) socket_context; - unsigned long long cnt; + switch (toe) + { + case MHD_CONNECTION_NOTIFY_STARTED: + active_connections++; + break; + case MHD_CONNECTION_NOTIFY_CLOSED: + active_connections--; + if (TEH_suicide && + (0 == active_connections) ) + GNUNET_SCHEDULER_shutdown (); + break; + } #if HAVE_DEVELOPER /* We only act if the connection is closed. */ if (MHD_CONNECTION_NOTIFY_CLOSED != toe) @@ -1651,15 +1718,6 @@ connection_done (void *cls, if (NULL != input_filename) GNUNET_SCHEDULER_shutdown (); #endif - cnt = req_count++; - if (req_max == cnt) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Restarting exchange service after %llu requests\n", - cnt); - (void) kill (getpid (), - SIGTERM); - } } @@ -1780,46 +1838,42 @@ run (void *cls, GNUNET_SCHEDULER_shutdown (); return; } - { - struct MHD_Daemon *mhd; - - mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME - | MHD_USE_PIPE_FOR_SHUTDOWN - | MHD_USE_DEBUG | MHD_USE_DUAL_STACK - | MHD_USE_TCP_FASTOPEN, - (-1 == fh) ? serve_port : 0, - NULL, NULL, - &handle_mhd_request, NULL, - MHD_OPTION_LISTEN_BACKLOG_SIZE, - (unsigned int) 1024, - MHD_OPTION_LISTEN_SOCKET, - fh, - MHD_OPTION_EXTERNAL_LOGGER, - &TALER_MHD_handle_logs, - NULL, - MHD_OPTION_NOTIFY_COMPLETED, - &handle_mhd_completion_callback, - NULL, - MHD_OPTION_NOTIFY_CONNECTION, - &connection_done, - NULL, - MHD_OPTION_CONNECTION_TIMEOUT, - connection_timeout, - (0 == allow_address_reuse) + mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME + | MHD_USE_PIPE_FOR_SHUTDOWN + | MHD_USE_DEBUG | MHD_USE_DUAL_STACK + | MHD_USE_TCP_FASTOPEN, + (-1 == fh) ? serve_port : 0, + NULL, NULL, + &handle_mhd_request, NULL, + MHD_OPTION_LISTEN_BACKLOG_SIZE, + (unsigned int) 1024, + MHD_OPTION_LISTEN_SOCKET, + fh, + MHD_OPTION_EXTERNAL_LOGGER, + &TALER_MHD_handle_logs, + NULL, + MHD_OPTION_NOTIFY_COMPLETED, + &handle_mhd_completion_callback, + NULL, + MHD_OPTION_NOTIFY_CONNECTION, + &connection_done, + NULL, + MHD_OPTION_CONNECTION_TIMEOUT, + connection_timeout, + (0 == allow_address_reuse) ? MHD_OPTION_END : MHD_OPTION_LISTENING_ADDRESS_REUSE, - (unsigned int) allow_address_reuse, - MHD_OPTION_END); - if (NULL == mhd) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to launch HTTP service. Is the port in use?\n"); - GNUNET_SCHEDULER_shutdown (); - return; - } - global_ret = EXIT_SUCCESS; - TALER_MHD_daemon_start (mhd); + (unsigned int) allow_address_reuse, + MHD_OPTION_END); + if (NULL == mhd) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to launch HTTP service. Is the port in use?\n"); + GNUNET_SCHEDULER_shutdown (); + return; } + global_ret = EXIT_SUCCESS; + TALER_MHD_daemon_start (mhd); atexit (&write_stats); #if HAVE_DEVELOPER |