[systemd-devel] Springboot and systemd, clean shutdown
Brian Reichert
reichert at numachi.com
Wed Oct 2 16:58:06 UTC 2024
My goal:
Under SLES12 SP5 running systemd-228, I want to cleanly terminate
a Java-based SpringBoot application.
My problem:
systemd (or at least the version available to me) seemingly is
terminating my JVM differently than my ExecStop directive should
yield.
Just for quick background, a SpringBoot application is a self-hosted
web server and web app, and you're excepted to interact with it via
'endpoints', basically several specific URLs.
According to the SpringBoot documentation, the desired way is to
POST to the shutdown URL.
https://docs.spring.io/spring-boot/api/rest/actuator/shutdown.html
Ignoring systemd: when the JVM is run is the foreground, using the
shutdown endpoint yields a clean exit:
10-153-68-12:/home/webapp # env SERVER_PORT=8888 LOG_DIR=/home/webapp/log
JDK_JAVA_OPTIONS=-Dlogging.config=log4j2.properties -Dloader.path=lib/
SPRING_MAIN_LAZY_INITIALIZATION=true /home/webapp/jdk/bin/java
-jar webapp.jar; echo $?
NOTE: Picked up JDK_JAVA_OPTIONS: -Dlogging.config=log4j2.properties
2024-10-02 12:20:24,685 main ERROR appender File has no parameter
that matches element Policies
0
10-153-68-12:/home/webapp # /usr/bin/curl -X POST localhost:8888/shutdown
{"message":"Shutting down, bye..."}
(Note the '0' exit status above.)
When I've started my service via my service file, if I manually
invoke the shutdown endpoint, I can see that the JVM exited with
0, but my ExecPost (using curl), was invoked, and that died as there
was no longer a listener:
10-153-68-12:/home/webapp # systemctl status webapp.service --full
webapp.service - example webapp
Loaded: loaded (/etc/systemd/system/webapp.service; disabled; vendor preset: disabled)
Active: failed (Result: exit-code) since Wed 2024-10-02 12:46:58 EDT; 7s ago
Process: 27573 ExecStop=/usr/bin/curl -X POST localhost:${SERVER_PORT}/shutdown (code=exited, status=7)
Process: 27434 ExecStart=/home/webapp/jdk/bin/java -jar ${JAR_FILE} ${JAR_ARGS} (code=exited, status=0/SUCCESS)
Main PID: 27434 (code=exited, status=0/SUCCESS)
Oct 02 12:46:40 10-153-68-12 systemd[1]: Started example webapp.
Oct 02 12:46:40 10-153-68-12 java[27434]: NOTE: Picked up JDK_JAVA_OPTIONS: -Dlogging.config=log4j2.properties -Dloader.path=lib/
Oct 02 12:46:42 10-153-68-12 java[27434]: 2024-10-02 12:46:42,417 main ERROR appender File has no parameter that matches element Policies
Oct 02 12:46:58 10-153-68-12 curl[27573]: % Total % Received % Xferd Average Speed Time Time Time Current
Oct 02 12:46:58 10-153-68-12 curl[27573]: Dload Upload Total Spent Left Speed
Oct 02 12:46:58 10-153-68-12 curl[27573]: [158B blob data]
Oct 02 12:46:58 10-153-68-12 curl[27573]: curl: (7) Failed to connect to localhost port 8888 after 2 ms: Couldn't connect to server
Oct 02 12:46:58 10-153-68-12 systemd[1]: webapp.service: Control process exited, code=exited status=7
Oct 02 12:46:58 10-153-68-12 systemd[1]: webapp.service: Unit entered failed state.
Oct 02 12:46:58 10-153-68-12 systemd[1]: webapp.service: Failed with result 'exit-code'.
I admit that's not a typical use case, so I'm not very worried, but
it would be nice to harden against that.
But it does show, that using curl to hit the shutdown endpoint does cause the JVM to exit cleanly.
But, my real concern is when I use systemd to stop this service, I
can see that curl was invoked, got content, and itself exited
cleanly, but somehow my JVM is exiting with an exit status of 143:
10-153-68-12:/home/webapp # systemctl status webapp.service --full
webapp.service - example webapp
Loaded: loaded (/etc/systemd/system/webapp.service; disabled; vendor preset: disabled)
Active: failed (Result: exit-code) since Wed 2024-10-02 12:30:22 EDT; 9s
ago
Process: 24220 ExecStop=/usr/bin/curl -X POST
localhost:${SERVER_PORT}/shutdown (code=exited, status=0/SUCCESS)
Process: 23462 ExecStart=/home/webapp/jdk/bin/java -jar ${JAR_FILE} ${JAR_ARGS} (code=exited, status=143)
Main PID: 23462 (code=exited, status=143)
Oct 02 12:27:20 10-153-68-12 java[23462]: NOTE: Picked up JDK_JAVA_OPTIONS: -Dlogging.config=log4j2.properties -Dloader.path=lib/
Oct 02 12:27:23 10-153-68-12 java[23462]: 2024-10-02 12:27:23,015 main ERROR appender File has no parameter that matches element Policies
Oct 02 12:30:21 10-153-68-12 systemd[1]: Stopping example webapp...
Oct 02 12:30:21 10-153-68-12 curl[24220]: % Total % Received % Xferd Average Speed Time Time Time Current
Oct 02 12:30:21 10-153-68-12 curl[24220]: Dload Upload Total Spent Left Speed
Oct 02 12:30:22 10-153-68-12 curl[24220]: [237B blob data]
Oct 02 12:30:22 10-153-68-12 systemd[1]: webapp.service: Main process exited, code=exited, status=143/n/a
Oct 02 12:30:22 10-153-68-12 systemd[1]: Stopped example webapp.
Oct 02 12:30:22 10-153-68-12 systemd[1]: webapp.service: Unit entered failed state.
Oct 02 12:30:22 10-153-68-12 systemd[1]: webapp.service: Failed with result 'exit-code'.
Further, when I compare logs, I can see that when I use the standalone
execution, I can see the Springboot app cleanly shuts down it's
listener; I don't see these entries when I use systemd to manage
this webapp:
[INFO ] 2024-10-02 12:27:20.656 [Thread-2] Http11NioProtocol - Pausing ProtocolHandler ["http-nio-8888"]
[INFO ] 2024-10-02 12:27:20.656 [Thread-2] StandardService - Stopping service [Tomcat]
[INFO ] 2024-10-02 12:27:20.658 [Thread-2] [/] - Destroying Spring FrameworkServlet 'dispatcherServlet'
[INFO ] 2024-10-02 12:27:20.661 [Thread-2] Http11NioProtocol - Stopping ProtocolHandler ["http-nio-8888"]
[INFO ] 2024-10-02 12:27:20.665 [Thread-2] Http11NioProtocol - Destroying ProtocolHandler ["http-nio-8888"]
Does anyone have any insight on why I'm seeing this?
Here's my service file:
10-153-68-12:/home/webapp # cat /etc/systemd/system/webapp.service
[Unit]
Description=example webapp
Before=getty at tty1.service plymouth-quit.service
DefaultDependencies=no
Requires=local-fs.target
After=local-fs.target
[Service]
User=webapp
Group=webapp
WorkingDirectory=/home/webapp
EnvironmentFile=/home/webapp/webapp.env
PassEnvironment=JAVA_HOME JDK_JAVA_OPTIONS JAR_FILE JAR_ARGS SERVER_PORT
ExecStart=/home/webapp/jdk/bin/java -jar ${JAR_FILE} ${JAR_ARGS}
ExecStop=/usr/bin/curl -X POST localhost:${SERVER_PORT}/shutdown
TimeoutStopSec=30
KillMode=mixed
NotifyAccess=all
Restart=no
[Install]
WantedBy=multi-user.target
--
Brian Reichert <reichert at numachi.com>
BSD admin/developer at large
More information about the systemd-devel
mailing list