<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Bug: Some apps don't react to SIGTERM and are killed after the 10 s stop timeout]]></title><description><![CDATA[<p dir="auto">While auditing one of my own packages I noticed this line in <code>journalctl -u docker</code>, once for every update of that app:</p>
<pre><code>Container failed to exit within 10s of signal 15 - using the force
</code></pre>
<p dir="auto">My <code>start.sh</code> ended with <code>exec gosu cloudron:cloudron python3 server.py</code>, so the app itself was PID 1, and PID 1 only receives SIGTERM if it installs a handler for it. To be clear upfront: nothing broke. The update takes 10 seconds longer and requests that are in flight get cut off, and for an app with SQLite in WAL mode that is harmless. I'm only posting because it turned out not to be limited to my own packages.</p>
<p dir="auto">I then looked at how long the stop takes for every app on my three servers (Cloudron 10.0.5), using the time between <code>stopContainer</code> and <code>deleteContainer</code> in the app task logs since 1 September:</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>App</th>
<th>PID 1</th>
<th>Stops that took 10 s or more</th>
</tr>
</thead>
<tbody>
<tr>
<td>Surfer (4 installs)</td>
<td><code>node /app/code/server.js …</code></td>
<td>16 of 16</td>
</tr>
<tr>
<td>MiroTalk SFU (3 installs)</td>
<td><code>npm start</code></td>
<td>12 of 12</td>
</tr>
<tr>
<td>IP2Location</td>
<td><code>node /app/code/index.js</code></td>
<td>4 of 4</td>
</tr>
<tr>
<td>Release Bell</td>
<td><code>node /app/code/index.js</code></td>
<td>2 of 2</td>
</tr>
</tbody>
</table>
<p dir="auto">For comparison, the apps with apache2 or supervisord as PID 1 (WordPress, Nextcloud, FreeScout, EspoCRM) stop in under 4 seconds, and so does another app that runs plain <code>node</code> as PID 1 but apparently handles the signal itself. A throwaway container from the Surfer image shows the same thing in isolation: plain <code>node</code> as PID 1 takes 10.1 s for <code>docker stop</code>, with a <code>process.on('SIGTERM')</code> handler 0.1 s, and with <code>docker run --init</code> also 0.1 s.</p>
<p dir="auto">In my own two packages I changed the last line of <code>start.sh</code> to <code>exec /usr/bin/tini -- gosu cloudron:cloudron python3 server.py</code> (tini is already in <code>cloudron/base</code>). The stop went from 10.2 s to 0.2 s and the line is gone from the docker log.</p>
<p dir="auto">Is this something you'd rather handle per package, or is the hard kill simply fine for these apps? I can imagine it matters little for something like Surfer, I was mostly surprised to see it in the log.</p>
]]></description><link>https://forum.cloudron.io/topic/16051/bug-some-apps-don-t-react-to-sigterm-and-are-killed-after-the-10-s-stop-timeout</link><generator>RSS for Node</generator><lastBuildDate>Wed, 07 Oct 2026 15:20:49 GMT</lastBuildDate><atom:link href="https://forum.cloudron.io/topic/16051.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 01 Oct 2026 19:50:30 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Bug: Some apps don't react to SIGTERM and are killed after the 10 s stop timeout on Fri, 02 Oct 2026 16:28:52 GMT]]></title><description><![CDATA[<p dir="auto">We have fixed some of the apps developed by us like surfer, calendearm, mail,.... to gracefully shut down handling the SIGTERM. Will be part of their next releases. So thanks for bringing this on the table good to have that improved!</p>
]]></description><link>https://forum.cloudron.io/post/130388</link><guid isPermaLink="true">https://forum.cloudron.io/post/130388</guid><dc:creator><![CDATA[nebulon]]></dc:creator><pubDate>Fri, 02 Oct 2026 16:28:52 GMT</pubDate></item><item><title><![CDATA[Reply to Bug: Some apps don't react to SIGTERM and are killed after the 10 s stop timeout on Fri, 02 Oct 2026 11:33:08 GMT]]></title><description><![CDATA[<p dir="auto">Ah that makes sense, I wasn't aware of the special handling there for PID 1. But yeah I think we should then fixup the apps instead.</p>
]]></description><link>https://forum.cloudron.io/post/130370</link><guid isPermaLink="true">https://forum.cloudron.io/post/130370</guid><dc:creator><![CDATA[nebulon]]></dc:creator><pubDate>Fri, 02 Oct 2026 11:33:08 GMT</pubDate></item><item><title><![CDATA[Reply to Bug: Some apps don't react to SIGTERM and are killed after the 10 s stop timeout on Fri, 02 Oct 2026 11:01:31 GMT]]></title><description><![CDATA[<p dir="auto">It's not the open handles, as far as I can tell. I tried it with a node process that has nothing open at all (<code>node -e "setInterval(()=&gt;{},1000)"</code> as PID 1 in a throwaway container from the Surfer image) and it behaves the same: it survives the SIGTERM and is killed after 10 s.</p>
<p dir="auto">What happens is that node's default SIGTERM handler doesn't shut anything down itself, it resets the handler and raises the signal again with the default action. For a normal process the default action is "terminate", so node exits right away, open sockets or not. But for PID 1 the kernel ignores signals that only have the default action, so the re-raised signal is dropped and node just keeps running. In <code>/proc/1/status</code> you can see the handler in <code>SigCgt</code> before the SIGTERM and gone after it, while the process is still there.</p>
<p dir="auto">That's also why tini makes a difference: node is then no longer PID 1, so the default action applies again and it exits in 0.1 s. Your idea works just as well and is the cleaner one: with a <code>process.on('SIGTERM')</code> handler in the app the signal is delivered even as PID 1, and the app can call close() on what matters before it exits.</p>
]]></description><link>https://forum.cloudron.io/post/130368</link><guid isPermaLink="true">https://forum.cloudron.io/post/130368</guid><dc:creator><![CDATA[imc67]]></dc:creator><pubDate>Fri, 02 Oct 2026 11:01:31 GMT</pubDate></item><item><title><![CDATA[Reply to Bug: Some apps don't react to SIGTERM and are killed after the 10 s stop timeout on Fri, 02 Oct 2026 10:54:29 GMT]]></title><description><![CDATA[<p dir="auto">Ah I see what you mean. Indeed might be worth looking into, taking surfer as an example, the nodejs process ends up as PID 1 but the default nodejs SIGTERM handler will not gracefully shutdown things like the database connection or close the expressjs socket, thus those keep hanging in there and preventing a clean shutdown. So it seems the solution for that is to keep track within the app and call <code>close()</code> on the relevant things.</p>
<p dir="auto">Though this brings up the question why using <code>tini</code> here changes anything in behavior about the shutdown?</p>
]]></description><link>https://forum.cloudron.io/post/130367</link><guid isPermaLink="true">https://forum.cloudron.io/post/130367</guid><dc:creator><![CDATA[nebulon]]></dc:creator><pubDate>Fri, 02 Oct 2026 10:54:29 GMT</pubDate></item><item><title><![CDATA[Reply to Bug: Some apps don't react to SIGTERM and are killed after the 10 s stop timeout on Fri, 02 Oct 2026 10:32:44 GMT]]></title><description><![CDATA[<p dir="auto">I think I explained it poorly, because I'm not suggesting to kill anything earlier or to shorten the timeout. The 10 s grace period is fine and should stay.</p>
<p dir="auto">My point is that the apps in the table never get the "please stop" in the first place. With the app as PID 1 and no handler installed, the kernel doesn't deliver the SIGTERM, so the app isn't using those 10 seconds to commit state: it just keeps running as if nothing happened and is then killed with SIGKILL. That is the forced kill you'd want to avoid, and for these apps it happens on every stop. With an init as PID 1 the signal does arrive and the app gets the same 10 seconds to finish, exactly the ctrl+c behaviour you describe.</p>
<p dir="auto">I agree the gain is small, so I'm fine leaving it at this. I mainly wanted to make sure it's a known thing.</p>
]]></description><link>https://forum.cloudron.io/post/130364</link><guid isPermaLink="true">https://forum.cloudron.io/post/130364</guid><dc:creator><![CDATA[imc67]]></dc:creator><pubDate>Fri, 02 Oct 2026 10:32:44 GMT</pubDate></item><item><title><![CDATA[Reply to Bug: Some apps don't react to SIGTERM and are killed after the 10 s stop timeout on Fri, 02 Oct 2026 10:03:52 GMT]]></title><description><![CDATA[<p dir="auto">not sure if this is worth optimizing with the extra risk that apps have less time to commit potential state to the database or disk. It is pretty standard on linux to tell the app to stop (like pressing ctrl+c in a process on the terminal). Depending on how many file/socket handles or other things are outstanding the runtimes can take their time. So instead of killing them with force earlier, the work then shifts to optimize shutdown behavior in each app, like listening to SIGTERM and trying to keep track of outstanding work, then deciding which is relevant and which isnt. All this seems more risky given the benefit of a rare action being faster, but maybe I am just not restarting apps often.</p>
]]></description><link>https://forum.cloudron.io/post/130363</link><guid isPermaLink="true">https://forum.cloudron.io/post/130363</guid><dc:creator><![CDATA[nebulon]]></dc:creator><pubDate>Fri, 02 Oct 2026 10:03:52 GMT</pubDate></item></channel></rss>