7

I'm currently trying to make a systemd service with two Fifo sockets. These sockets map to stdout and stdin of the application. I'm currently using the following configuration files.

foo.service

[Unit]
Description=foo Fifo test
After=network.target foo-in.socket foo-out.socket
Requires=foo-in.socket foo-out.socket

[Service]
Sockets=foo-out.socket
Sockets=foo-in.socket
StandardOutput=fd:foo-out.socket
StandardInput=fd:foo-in.socket
StandardError=journal
ExecStart=/path/to/foo/exec

foo-out.socket

[Unit]
Description=foo Task Writes to this

[Socket]
Service=foo.service
ListenFIFO=%t/foo/out

foo-in.socket

[Unit]
Description=foo Task reads commands from this

[Socket]
Service=foo.service
ListenFIFO=/run/user/1000/foo/in

I can start the service using the commands systemctl --user daemon-reload and systemctl --user start foo. The problem comes when I try stopping foo.service. I receive this message:

Warning: Stopping foo.service, but it can still be activated by:
  foo-in.socket
  foo-out.socket

Is there a way to stop the sockets automatically when the service is stopped?

1
  • 1
    Generally speaking, I avoid directly starting and stopping any service that uses a socket. Instead, I start/stop the socket directly. In your case - with two sockets - you probably want a target that Wants both sockets, which are both PartOf the target. Then you can manage the whole thing using the target, rather than the service. Commented Aug 1, 2019 at 17:08

4 Answers 4

3

Here's a good example that can be manually shutdown. The example here is in attempt to shutdown the 'docker' service.

root@localhost:~# systemctl stop docker
Warning: Stopping docker.service, but it can still be activated by:
   docker.socket

root@llocalhost:~# systemctl stop docker.socket

root@logicaldoc:~# ps aux | grep docker
root      1519  0.0  0.0  14220   924 pts/0    S+   17:41   0:00 grep --color=auto docker
1
  • 1
    This is not a solution to use with systemd service file. Commented Sep 3, 2021 at 4:19
2

ExecStopPost Method

You can use the [Service] block's ExecStopPost= option to run arbitrary commands when the service stops either after successful completion or as a result of a failure.

Example

Only the last line has been updated.

[Unit]
Description=foo Fifo test
After=network.target foo-in.socket foo-out.socket
Requires=foo-in.socket foo-out.socket

[Service]
Sockets=foo-out.socket
Sockets=foo-in.socket
StandardOutput=fd:foo-out.socket
StandardInput=fd:foo-in.socket
StandardError=journal
ExecStart=/path/to/foo/exec
ExecStopPost=systemctl --user stop foo-out.socket ; systemctl --user stop foo-in.socket

Source: systemd.service (emphasis mine)

Additional commands that are executed after the service is stopped. This includes cases where the commands configured in ExecStop= were used, where the service does not have any ExecStop= defined, or where the service exited unexpectedly. This argument takes multiple command lines, following the same scheme as described for ExecStart=. Use of these settings is optional. Specifier and environment variable substitution is supported. Note that – unlike ExecStop= – commands specified with this setting are invoked when a service failed to start up correctly and is shut down again.

It is recommended to use this setting for clean-up operations that shall be executed even when the service failed to start up correctly. Commands configured with this setting need to be able to operate even if the service failed starting up half-way and left incompletely initialized data around. As the service's processes have been terminated already when the commands specified with this setting are executed they should not attempt to communicate with them.

Note that all commands that are configured with this setting are invoked with the result code of the service, as well as the main process' exit code and status, set in the $SERVICE_RESULT, $EXIT_CODE and $EXIT_STATUS environment variables, see systemd.exec(5) for details.

Note that the execution of ExecStopPost= is taken into account for the purpose of Before=/After= ordering constraints.

1

Add ExecStopPost=/rm (socket pathname) into the /etc/systemctl/system/(???).socket definition, which is a started by the (???).service via "Requires=???.socket".

To remove the socket, stop the service, then also stop the socket. If you do not stop the socket, any client writing to the socket will reactivate the service, as per it's message when you stop the service:

Warning: Stopping (???).service, but it can still be activated by: (???).socket

1

Instead of adding ExecStopPost=systemctl ..., I would rely on systemd's predefined relationship PartOf=.

From the 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.

       When PartOf=b.service is used on a.service, this dependency will show as
       ConsistsOf=a.service in property listing of b.service.  ConsistsOf=
       dependency cannot be specified directly.

In foo-out.socket and foo-in.socket, you can add PartOf=foo.service in your [Unit] section. Then, when foo.service is stopped, the sockets get stopped.


foo.service (untouched)

[Unit]
Description=foo Fifo test
After=network.target foo-in.socket foo-out.socket
Requires=foo-in.socket foo-out.socket

[Service]
Sockets=foo-out.socket
Sockets=foo-in.socket
StandardOutput=fd:foo-out.socket
StandardInput=fd:foo-in.socket
StandardError=journal
ExecStart=/path/to/foo/exec

foo-out.socket

[Unit]
Description=foo Task Writes to this
PartOf=foo.service

[Socket]
Service=foo.service
ListenFIFO=%t/foo/out

foo-in.socket

[Unit]
Description=foo Task reads commands from this
PartOf=foo.service

[Socket]
Service=foo.service
ListenFIFO=/run/user/1000/foo/in
3
  • This doesn't seem to work when services go into an inactive state (by exiting with success and Restart=on-failure or similar)--is there a way to have the socket stop in this case? Commented Oct 10, 2023 at 16:29
  • When the process closes, I think EOF is sent along the socket to the consumer. In most cases, the other end will close the socket upon receiving an EOF. In the case above, I was testing everything with netcat which does close the socket and exit itself when EOF is received. Commented Oct 11, 2023 at 7:11
  • I see, so it might work if my service closed the socket, I'll have to give that a try. I was trying to avoid reactivation which I was able to fix with remainafterexit. But closing may be a better solution. Commented Oct 14, 2023 at 18:03

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.