From: Michael Tremer Date: Tue, 13 Aug 2024 18:04:29 +0000 (+0000) Subject: daemon: Automatically try to reconnect when the connection gets lost X-Git-Tag: 0.9.30~1209 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=de1d283188655c8e98f9d2177c6dfc8d0c612372;p=pakfire.git daemon: Automatically try to reconnect when the connection gets lost Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/daemon.c b/src/libpakfire/daemon.c index bb5c5d306..3c37c87b8 100644 --- a/src/libpakfire/daemon.c +++ b/src/libpakfire/daemon.c @@ -38,6 +38,10 @@ struct pakfire_daemon { // Event Loop sd_event* loop; + + // Connection Timer and Holdoff Time + sd_event_source* connect_timer; + unsigned int reconnect_holdoff; }; static int pakfire_daemon_terminate(sd_event_source* source, @@ -49,6 +53,108 @@ static int pakfire_daemon_terminate(sd_event_source* source, return sd_event_exit(sd_event_source_get_event(source), 0); } +/* + Called when a new job has been received +*/ +static int pakfire_daemon_job(struct pakfire_daemon* daemon, json_object* m) { + return 0; +} + +static int pakfire_daemon_recv(struct pakfire_xfer* xfer, + const char* message, const size_t size, void* data) { + struct pakfire_daemon* daemon = data; + struct json_object* type = NULL; + struct json_object* m = NULL; + int r; + + // Reset the holdoff timer + daemon->reconnect_holdoff = 1000000; + + // Parse the JSON message + m = pakfire_json_parse(daemon->ctx, message, size); + if (!m) { + r = -errno; + goto ERROR; + } + + // Fetch the message type + if (!json_object_object_get_ex(m, "type", &type)) { + CTX_ERROR(daemon->ctx, "Invalid message with missing type\n"); + + return -EINVAL; + } + + // Fetch the type + const char* t = json_object_get_string(type); + + // Handle new jobs + if (strcmp(t, "job") == 0) { + r = pakfire_daemon_job(daemon, m); + + } else { + CTX_ERROR(daemon->ctx, "Unknown message. Ignoring:\n%s\n", + json_object_to_json_string_ext(m, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY)); + + r = 0; + } + +ERROR: + if (m) + json_object_put(m); + + return r; +} + +/* + This function is called whenever the connection to the build service could not + be established or was interrupted. It will try to reconnect. +*/ +static int pakfire_daemon_close(struct pakfire_xfer* xfer, int code, void* data) { + struct pakfire_daemon* daemon = data; + int r; + + CTX_INFO(daemon->ctx, "Will attempt to reconnect in %u second(s)\n", + daemon->reconnect_holdoff / 1000000); + + // Set the reconnection timer + r = sd_event_source_set_time_relative(daemon->connect_timer, daemon->reconnect_holdoff); + if (r < 0) { + CTX_ERROR(daemon->ctx, "Could not set the reconnection timer: %s\n", strerror(-r)); + return r; + } + + // Activate the timer + r = sd_event_source_set_enabled(daemon->connect_timer, SD_EVENT_ONESHOT); + if (r < 0) { + CTX_ERROR(daemon->ctx, "Could not activate the connect timer: %s\n", strerror(-r)); + return r; + } + + // Double the holdoff time + daemon->reconnect_holdoff *= 2; + + // Cap reconnection attempts to every minute + if (daemon->reconnect_holdoff > 60000000) + daemon->reconnect_holdoff = 60000000; + + return 0; +} + +static int pakfire_daemon_connect(sd_event_source* s, uint64_t usec, void* data) { + struct pakfire_daemon* daemon = data; + int r; + + CTX_INFO(daemon->ctx, "Connecting...\n"); + + // Connect to the build service + r = pakfire_buildservice_daemon(daemon->service, + pakfire_daemon_recv, NULL, pakfire_daemon_close, daemon); + if (r) + CTX_ERROR(daemon->ctx, "Connection attempt failed\n"); + + return r; +} + static int pakfire_daemon_setup_loop(struct pakfire_daemon* daemon) { int r; @@ -56,14 +162,14 @@ static int pakfire_daemon_setup_loop(struct pakfire_daemon* daemon) { r = sd_event_default(&daemon->loop); if (r < 0) { CTX_ERROR(daemon->ctx, "Could not setup event loop: %s\n", strerror(-r)); - return 1; + return r; } // Enable the watchdog r = sd_event_set_watchdog(daemon->loop, 1); if (r < 0) { CTX_ERROR(daemon->ctx, "Could not activate watchdog: %s\n", strerror(-r)); - return 1; + return r; } // Listen for SIGTERM @@ -71,7 +177,7 @@ static int pakfire_daemon_setup_loop(struct pakfire_daemon* daemon) { pakfire_daemon_terminate, daemon); if (r < 0) { CTX_ERROR(daemon->ctx, "Could not register handling SIGTERM: %s\n", strerror(-r)); - return 1; + return r; } // Listen for SIGINT @@ -79,13 +185,23 @@ static int pakfire_daemon_setup_loop(struct pakfire_daemon* daemon) { pakfire_daemon_terminate, daemon); if (r < 0) { CTX_ERROR(daemon->ctx, "Could not register handling SIGINT: %s\n", strerror(-r)); - return 1; + return r; + } + + // Setup the reconnection timer + r = sd_event_add_time_relative(daemon->loop, &daemon->connect_timer, + CLOCK_MONOTONIC, 0, 0, pakfire_daemon_connect, daemon); + if (r < 0) { + CTX_ERROR(daemon->ctx, "Could not register the connection timer: %s\n", strerror(-r)); + return r; } return 0; } static void pakfire_daemon_free(struct pakfire_daemon* daemon) { + if (daemon->connect_timer) + sd_event_source_unref(daemon->connect_timer); if (daemon->service) pakfire_buildservice_unref(daemon->service); if (daemon->loop) @@ -120,6 +236,9 @@ int pakfire_daemon_create(struct pakfire_daemon** daemon, struct pakfire_ctx* ct if (r) goto ERROR; + // Reconnect after one second + d->reconnect_holdoff = 1000000; + // Return the pointer *daemon = d; @@ -146,55 +265,6 @@ struct pakfire_daemon* pakfire_daemon_unref(struct pakfire_daemon* daemon) { return NULL; } -/* - Called when a new job has been received -*/ -static int pakfire_daemon_job(struct pakfire_daemon* daemon, json_object* m) { - return 0; -} - -static int pakfire_daemon_recv(struct pakfire_xfer* xfer, - const char* message, const size_t size, void* data) { - struct pakfire_daemon* daemon = data; - struct json_object* type = NULL; - struct json_object* m = NULL; - int r; - - // Parse the JSON message - m = pakfire_json_parse(daemon->ctx, message, size); - if (!m) { - r = -errno; - goto ERROR; - } - - // Fetch the message type - if (!json_object_object_get_ex(m, "type", &type)) { - CTX_ERROR(daemon->ctx, "Invalid message with missing type\n"); - - return -EINVAL; - } - - // Fetch the type - const char* t = json_object_get_string(type); - - // Handle new jobs - if (strcmp(t, "job") == 0) { - r = pakfire_daemon_job(daemon, m); - - } else { - CTX_ERROR(daemon->ctx, "Unknown message. Ignoring:\n%s\n", - json_object_to_json_string_ext(m, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY)); - - r = 0; - } - -ERROR: - if (m) - json_object_put(m); - - return r; -} - static int pakfire_daemon_loop(struct pakfire_daemon* daemon) { int r; @@ -220,13 +290,5 @@ ERROR: } int pakfire_daemon_main(struct pakfire_daemon* daemon) { - int r; - - // Connect to the build service - r = pakfire_buildservice_daemon(daemon->service, - pakfire_daemon_recv, NULL, NULL, daemon); - if (r) - return r; - return pakfire_daemon_loop(daemon); }