Graceful shutdown request signal

Daniel Gröber dxld at darkboxed.org
Wed Jun 21 01:03:50 CEST 2023


Hi Erin,

On Tue, Jun 20, 2023 at 08:20:50PM +0200, Erin Shepherd wrote:
> I run bird on a system which uses systemd as a service supervisor, and
> would like to implement graceful restart in a way which works well with
> it.

I'm also interested in getting this working. I'm wondering how graceful
restart is supposed to behave to begin with though. Last time I just tried
`birdc graceful restart` I was surprised that this actually makes bird exit
with rv=0 instead of ... well actually restarting.

Is that normal or a bug in the Debian packaging/systemd service?

I suppose if you're supposed to use graceful restart just before rebooting
the system it makes sense but at the time I just wanted to do a full
restart to update the running bird executable without causing traffic
disruption and was rather surprised when it didn't come back up.

> In particular, what I'd like to do is:
>  • If I restart the bird service (e.g. for an upgrade), Bird performs a graceful restart
>  • If I manually stop bird (systemctl stop bird2), shutdown the system, or any other action which is liable to cause a longer period of downtime, perform a graceful restart (for BGP at least)

When you want to tickle special behaviour out of systemd I found it best to
not try and do everything in one unit. Using the dependency system you can
stop another unit before bird.service gets stopped, this can then call
birdc graceful restart, like this:

bird-graceful-restart.service:

    [Unit]
    After=bird.service
    Requires=bird.service
    [Service]
    Type=oneshot
    RemainAfterExit=yes
    ExecStop=birdc graceful restart
    [Install]
    WantedBy=bird.service

That way you can enable/disable system wide graceful bird restart by
`systemctl enable bird-graceful-restart.service`.

The BindsTo+After means stopping bird.service (which is part of restart)
will first stop bird-graceful-restart.service, which can then casually
signal bird to perform graceful restart without a race (I
think). WanteBy=bird.service is needed as ExecStop will only run when a
service has actually been started.

Also some special handling for the case where bird is already gone (crashed
or exited) and birdc would fail might be needed. Excercise for the reader :)

Doing some quick testing this actually seems to do what I want. Somewhat
unexpectedly `systemctl restart bird.servce` with the above enabled does
then actually do what you'd expect since restart is just stop+start. Bird
will exit on getting the graceful restart command so systemd can't try to
stop it some more but the subsequent start will make it come back up. Neat.

On system shutdown only the stop part will happen so bird exiting is
actully useful now and that too should work as expected.

> Ideally systemd would have an ExecStopRestart option which could be used
> to distinguish between stops and restarts, but unfortunately it doesn't
> (I might submit a feature request for this regardless). However, it does
> support `KillSignal and RestartKillSignal options.`

I've been perplexed by this in the past also. Don't even get me started on
the fact that ExecStop= runs even when a service already terminated on it's
own, to like stop it some more... :)

The semantics are really bonkers sometimes but it's actually rather
flexible if you look at the nuaunces of the different dependency types a
bit.

--Daniel


More information about the Bird-users mailing list