I have a script that installs and sets up traffic server:
yum install -y trafficserver
systemctl start trafficserver
traffic_line -s proxy.config.url_remap.remap_required -v 0
traffic_line -s proxy.config.reverse_proxy.enabled -v 0
The problem is, traffic_line
fails with:
[connect] ERROR (main_socket_fd 3): No such file or directory error: could not connect to management port, make sure traffic_manager is running
This is because systemctl start
returns immediately, without waiting for traffic server to be actually started.
Is there a way to tell systemctl start
to only return once the service is started?
If this is not possible, is there a command that I can run after systemctl start
to actually wait for the service to be started?
systemctl start
does wait for the service to be ready (except if invoked with--no-block
), the service just needs to indicate that properly (i. e., not useType=simple
). If the service doesn’t tell systemd when it’s ready, no variation ofsystemctl is-active
,systemctl show
, etc. will help you.The most elegant solution, as mentioned in the comments, would be a socket unit. systemd starts the socket,
traffic_line
connects to it, systemd starts the service, andtraffic_line
blocks until the service starts to accept connections on the file descriptor it inherited from systemd.Alternatively, you can use either
Type=forking
(the service forks, and the main PID exits once the forked service is ready) orType=notify
(the service callssd_notify(0, "READY=1")
once it’s ready).Unfortunately, all of these solutions require some support from
trafficserver
– use systemd’s socket instead of allocating its own, fork and wait appropriately in the main process, or callsd_notify
. systemd can’t magically guess when the server is ready if the server doesn’t cooperate :)After looking at
trafficserver
’s source code a bit, it looks like it might actually supportType=forking
– the server is spawned by a dedicatedtraffic_cop
command, which seems to wait until the server is up and perform some basic testing (at least the code looks like it). So if you change the service type, it might just work:I finally got it to work, after several attempts.
First attempt
After digging into systemctl help I found the
is-active
command:I therefore wrote a shell script to wait until the service becomes active:
Unfortunately, even though this script works as expected when I test it with start/stop, I was still getting the same error when running the
traffic_line
commands right after it. I think that the service is reported as active before the actual processes have fully started (probably a matter of milliseconds).Second attempt
So I tried another way. Knowing that this is the very first start of the service, I can wait until the PID file of the trafficserver manager exists. Here is what I tried:
Same problem: when the trafficserver manager's PID file is written, the manager is not actually ready to receive orders yet, so I'm still getting the error.
Damn, I don't want to use a blind
sleep
.Third attempt
So I ended up checking that the
traffic_line
command itself does not fail:And this works!
Nice, but...
Unfortunately, the answer is very specific to the service I'm using (trafficserver), and would not directly apply to other services.
If you know a more generic answer to this question, please feel free to share it.
I'm bad in shells scripting, but I think that you'd want to test for both, the ActiveState and the SubState property if the return active and running respectively.
After that you should be able to run the second portion of your script.
Simplest way would be to add a sleep to the script:
Or you could do some job control as here