WL#13707: add systemd notify support
Motivation
MySQL Router currently interacts with systemd through pid-file and exit-codes.
systemd allow more detailed status information to be reported back like:
READY=1
to report a service is ready to handle connectionsRELOADING=1
in case config is reread and service is currently not readySTOPPING=1
in case if shutting down
Futher reading: http://0pointer.de/public/systemd-man/sd_notify.html
- R1
-
If there is a
NOTIFY_SOCKET
environment variable set when the Router starts, the Router MUST treat the value of this variable as the name of the unix-domain socket, DGRAM on all unix-based OSes - R2
-
On Windows it MUST treat the
NOTIFY_SOCKET
as a named pipe path. - R3
-
If that
NOTIFY_SOCKET
is set the Router MUST write "READY=1" to the platform specific IPC channel pointed by it when all its components are fully initialized. - R4
- The Router MUST declare that it is ready when all the plugin instances that are provisioned in the current running configuration are ready. Some of the plugins are only a helper plugins that do not expose any user-visible readiness (like logger, http_auth_backend etc). The others need to explicitly declare that they are fully initialized and ready to provide their service.
- R4.1
- Additionally on the Unix-based OSes also the interrupt handler has to be set up in order for the Router to declare it is ready.
- R5
- If there is no plugin that declares the readiness configured the Router itself MUST declare that it is ready at the initialization.
- R6
-
When the
NOTIFY_SOCKET
environment variable is not set or empty the Router MUST skip the step of declaring it is ready and continue working as before introducing this WL. - R7
- The Router MUST attempt writing to the notify socket only once, when the last of the configured plugins becomes ready. If that fails, a warning MUST get logged and the Router MUST continue working as before introducing this WL.
- R8
-
If there is a
NOTIFY_SOCKET
environment variable set when the Router is shutting down, the Router should write the "STOPPING=1" to the IPC channel pointed by theNOTIFY_SOCKET
- R9
- The systemd support should be integrated with the packaging scripts for the OSes that support it (deb, rpm)
- R10
- Router should not send no READY nor STOPPING notifications when it is being ran for the bootstrap (bootstrap mode)
Plugin is ready
- There are currently server plugins that provides some service, either to the Router user or to the other Router plugins. These should notify when their service is ready.
-
- the
routing
plugin instance (one for each configured routing section) is ready when it set up the network endpoint (whether it is TCP or unix socket) and it is ready to accept the client connections on that endpoint.
- the
-
- the
metadata_cache
plugin is ready when it connected to one of the configured metadata servers and successfully fetched the Cluster metadata.
- the
-
- the
http_server
plugin is ready when it set up the network endpoint and is ready to serve the http requests.
- the
-
- the
rest_api
,rest_metadata_cache
,rest_router
andrest_routing
plugins are ready when they successfully added the relevant html paths to thehttp_server
- the
Implementation
For the Router to be able to collect the readiness of all the configured plugin instances the Plugin
struct is extended with additional boolean field.
struct Plugin {
//..
bool declares_readiness;
}
If the given plugin sets true
in that field that means it is required to call the mysql_harness::on_plugin_ready();
whenever it initialized and ready to serve it's purpose. Usually that should be done somewhere in the start()
once the service has started and the plugin enters the service loop.
That lets the Loader to know how many plugin instances there are configured that have to declare their readiness before the Router can declare it is ready itself. Before calling the start_all()
the Router counts the number of those plugins and sets a global variable num_of_non_ready_plugin_instances
to that number.
Each plugin that has declares_readiness=true
at some point, when it is fully initialized, calls:
void on_plugin_ready(const std::string &name) {
log_debug("Plugin %s ready", name.c_str());
if (--num_of_non_ready_plugin_instances == 0) {
log_debug("Service ready!");
notify_ready();
}
}