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=1to report a service is ready to handle connectionsRELOADING=1in case config is reread and service is currently not readySTOPPING=1in case if shutting down
Futher reading: http://0pointer.de/public/systemd-man/sd_notify.html
- R1
-
If there is a
NOTIFY_SOCKETenvironment 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_SOCKETas a named pipe path. - R3
-
If that
NOTIFY_SOCKETis 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_SOCKETenvironment 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_SOCKETenvironment 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
routingplugin 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_cacheplugin is ready when it connected to one of the configured metadata servers and successfully fetched the Cluster metadata.
- the
-
- the
http_serverplugin 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_routerandrest_routingplugins 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();
}
}