How to Restart a Service If Its Dependent Service Is Restarted

How to restart a service if its dependent service is restarted

You can use PartOf.

[Unit]
After=foo.service
Requires=foo.service
PartOf=foo.service

From the systemd.unit man page:

PartOf=

Configures dependencies similar to Requires=, but limited to stopping and restarting of units. When systemd stops or restarts the units listed here, the action is propagated to this unit. Note that this is a one-way dependency — changes to this unit do not affect the listed units.

Restart a service with dependent services?

Alright, finally implemented this. I've posted it as a separate answer as I had already come to this conclusion in the original update to my question, which was posted prior to the first answer.

Again, the StartService(), StopService() and RestartService() methods follow the conventions outlined in the examples and such already referenced in the question itself (i.e. they wrap Start/Stop behavior to avoid "already started/stopped"-type exceptions) with the addendum that if a Service is passed in (as is the case below), Refresh() is called on that service before checking its Status.

public static void RestartServiceWithDependents(ServiceController service, TimeSpan timeout)
{
int tickCount1 = Environment.TickCount; // record when the task started

// Get a list of all services that depend on this one (including nested
// dependencies)
ServiceController[] dependentServices = service.DependentServices;

// Restart the base service - will stop dependent services first
RestartService(service, timeout);

// Restore dependent services to their previous state - works because no
// Refresh() has taken place on this collection, so while the dependent
// services themselves may have been stopped in the meantime, their
// previous state is preserved in the collection.
foreach (ServiceController dependentService in dependentServices)
{
// record when the previous task "ended"
int tickCount2 = Environment.TickCount;
// update remaining timeout
timeout.Subtract(TimeSpan.FromMilliseconds(tickCount2 - tickCount1));
// update task start time
tickCount1 = tickCount2;
switch (dependentService.Status)
{
case ServiceControllerStatus.Stopped:
case ServiceControllerStatus.StopPending:
// This Stop/StopPending section isn't really necessary in this
// case as it doesn't *do* anything, but it's included for
// completeness & to make the code easier to understand...
break;
case ServiceControllerStatus.Running:
case ServiceControllerStatus.StartPending:
StartService(dependentService, timeout);
break;
case ServiceControllerStatus.Paused:
case ServiceControllerStatus.PausePending:
StartService(dependentService, timeout);
// I don't "wait" here for pause, but you can if you want to...
dependentService.Pause();
break;
}
}
}

How can I configure a systemd service to restart periodically?

Yes, you can make your service to restart it periodically by making your service of Type=notify.
Add this option in [Service] section of your service file along with Restart=always and give WatchdogSec=xx, where xx is the time period in second you want to restart your service. Here your process will be killed by systemd after xx time period and will be restarted by systemd again.
for eg.

[Unit]
.
.

[Service]
Type=notify
.
.
WatchdogSec=10
Restart=always
.
.

[Install]
WantedBy= ....

Systemd timer for a bound service restarts the service it is bound to

Here are the simplest units that meet your constraints:

test-a.service

[Service]              
ExecStart=sleep 3600 # long-running command

test-b.service

[Service]     
ExecStart=date # short command

test-b.timer

[Unit]                                
After=test-a.service
BindsTo=test-a.service # makes test-b.timer stop when test-a.service stops

[Timer]
OnCalendar=* *-*-* *:*:00

[Install]
WantedBy=test-a.service # makes test-b.timer start when test-a.service starts

Don't forget to

  • systemctl daemon-reload
  • systemctl disable test-b.timer
  • systemctl enable test-b.timer
    To apply the changes in the [Install] section.

Explanations:

  • what you want is to bind a.service with b.timer, not b.service
  • b.service is only a short command, and systemctl start b.service will only run the command, not start the associated timer
  • only systemctl start b.timer will start the timer
  • The WantedBy tells systemd to start test-b.timer when test-a.service starts
  • The BindsTo tells test-b.timer to stop when test-a.service stops
  • The After only ensures that test-b.timer is not started at the same time than test-a.service: it will force systemd to start test-b.timer after test-a.service has finished starting.

About the behaviour you observed:

  • When you stopped your a.service, the b.timer was still active and it tried starting b.service to run its short command. Since your b.service specified BindsTo=a.service, systemd thought that b.service required a.service to be started also, and effectively restarted a.service for b.service to run correctly.

Automatically restart a service after unattended updates under systemd

Use Restart=always if you want it to run at all times. When mysql service update happens, this service does a clean stop and therefore systemd doesn't restart it. You have Restart=on-failure set, which only restarts if the stop has a return code other than 0.

Restart = always
RestartSec = 10

RestartSec

Configures the time to sleep before restarting a service (as configured with Restart=). Takes a unit-less value in seconds, or a time span value such as "5min 20s". Defaults to 100ms.



Related Topics



Leave a reply



Submit