Skip to content

Instantly share code, notes, and snippets.

@tom--
Last active October 14, 2017 19:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tom--/88a920215171a487dbcec4b107c6e7e2 to your computer and use it in GitHub Desktop.
Save tom--/88a920215171a487dbcec4b107c6e7e2 to your computer and use it in GitHub Desktop.
Controling a group of daemons and timer jobs with a systemd target

Controling a group of daemons and timer jobs with a systemd target

Scenario

The custom web application My App, in addition to its web server request-driven work, has three daemons (able, baker and charlie) and three jobs (dog, easy and fox) that run (cron-like) on a pre-defined schedule.

Requirements

The app needs these all to be in one of two states

State description
Up all the daemons are running and the jobs run according to their respective schedules
Down all daemons are stopped and the jobs do not run

We want to use systemd to

  • enforce this Up/Down policy,
  • give the operator (and scripts etc.) a means to switch between Up and Down states, and
  • start the daemons and jobs at an appropriate stage of system startup (in this case that is not before the local MariaDB database service is up).

Design

  • Install a custom systemd target unit myapp_master.target on which to use systemctl commands
  • Use one service unit to mange each of the daemons
  • For each job, use a systemd timer unit, each with a corresponding service unit to run the job
  • Make the daemon service and timer units depend on the master target

See the unit files for details.

# myapp_able.service
[Unit]
Description=My App Able daemon
After=myapp_master.target
BindsTo=myapp_master.target
[Service]
ExecStart=/usr/local/bin/myapp_daemon Able
Restart=always
[Install]
WantedBy=myapp_master.target
# myapp_baker.service
[Unit]
Description=My App Baker daemon
After=myapp_master.target
BindsTo=myapp_master.target
[Service]
ExecStart=/usr/local/bin/myapp_daemon Baker
Restart=always
[Install]
WantedBy=myapp_master.target
# myapp_charlie.service
[Unit]
Description=My App Charlie daemon
After=myapp_master.target
BindsTo=myapp_master.target
[Service]
ExecStart=/usr/local/bin/myapp_daemon Charlie
Restart=always
[Install]
WantedBy=myapp_master.target
#!/usr/bin/env php
<?php
array_shift($argv);
$name = 'My App: ' . (implode(' ', $argv) ?: bin2hex(random_bytes(4))) . ' (' . posix_getpid() . ')';
$signals = [
SIGTERM => 'TERM',
SIGINT => 'INT',
SIGHUP => 'HUP',
SIGUSR1 => 'USR1',
SIGUSR2 => 'USR2',
];
function signalHandler(int $signalNumber)
{
global $name, $signals;
echo "$name received {$signals[$signalNumber]} signal.";
if (in_array($signalNumber, [SIGTERM, SIGINT])) {
echo " Exiting\n";
exit;
}
echo "\n";
}
foreach ($signals as $signal => $ignore) {
pcntl_signal($signal, "signalHandler");
}
echo "$name started.\n";
while (true) {
usleep(100000);
pcntl_signal_dispatch();
}
# myap_dog.service
[Unit]
Description=My App Dog job
[Service]
Type=oneshot
ExecStart=/bin/echo My App job Dog ran!
# myapp_dog.timer
[Unit]
Description=My App Dog timer job
Requires=myapp_master.target
[Timer]
OnCalendar=*:*:00
Persistent=true
[Install]
WantedBy=myapp_master.target
# myap_easy.service
[Unit]
Description=My App Easy job
[Service]
Type=oneshot
ExecStart=/bin/echo My App job Easy ran!
# myapp_easy.timer
[Unit]
Description=My App Easy timer job
Requires=myapp_master.target
[Timer]
OnCalendar=*:*:20
Persistent=true
[Install]
WantedBy=myapp_master.target
# myap_fox.service
[Unit]
Description=My App Fox job
[Service]
Type=oneshot
ExecStart=/bin/echo My App job Fox ran!
# myapp_fox.timer
[Unit]
Description=My App Fox timer job
Requires=myapp_master.target
[Timer]
OnCalendar=*:*:40
Persistent=true
[Install]
WantedBy=myapp_master.target
# test_master.target
[Unit]
Description=My App daemon and job master
After=mariadb.service
[Install]
WantedBy=multi-user.target
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment