<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Systemd on Margrop Blog</title>
    <link>https://blog.margrop.net/en/categories/systemd/</link>
    <description>Recent content in Systemd on Margrop Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-US</language>
    <lastBuildDate>Fri, 19 Jun 2026 10:58:00 +0800</lastBuildDate>
    <atom:link href="https://blog.margrop.net/en/categories/systemd/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Ubuntu shutdown stuck for 90 seconds? A Python asyncio service that won&#39;t honour SIGTERM, and how to fix it</title>
      <link>https://blog.margrop.net/en/post/ubuntu-shutdown-stuck/</link>
      <pubDate>Fri, 19 Jun 2026 10:58:00 +0800</pubDate>
      <guid>https://blog.margrop.net/en/post/ubuntu-shutdown-stuck/</guid>
      <description>&lt;blockquote&gt;&#xA;&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;After upgrading my home proxy box to Ubuntu 24.04, &lt;code&gt;systemctl reboot&lt;/code&gt; stopped being fast: SSH would hang on for &lt;strong&gt;90 seconds&lt;/strong&gt; before the box actually shut down. &lt;code&gt;journalctl&lt;/code&gt; made it obvious: &lt;code&gt;smart-proxy.service: State &#39;stop-sigterm&#39; timed out. Killing.&lt;/code&gt; — systemd sent SIGTERM, waited 90 seconds, nobody reacted, and SIGKILL was the only option left.&lt;/p&gt;&#xA;&lt;p&gt;The root cause is not systemd&amp;rsquo;s fault and not Ubuntu&amp;rsquo;s fault. It is &lt;strong&gt;Python&amp;rsquo;s asyncio runtime not actually ending its child tasks when SIGTERM arrives&lt;/strong&gt; — it is parked on a &lt;code&gt;socket.recv&lt;/code&gt; and never voluntarily looks at the signal queue.&lt;/p&gt;&#xA;&lt;p&gt;The fix has two halves, both required: &lt;strong&gt;(1)&lt;/strong&gt; a systemd drop-in that lowers &lt;code&gt;TimeoutStopSec&lt;/code&gt; from the default 90s down to 20s on the affected Python units; &lt;strong&gt;(2)&lt;/strong&gt; inside the Python service itself, walk &lt;code&gt;asyncio.all_tasks()&lt;/code&gt;, &lt;code&gt;.cancel()&lt;/code&gt; the in-flight connection handlers on SIGTERM, and wrap &lt;code&gt;self.stop()&lt;/code&gt; in &lt;code&gt;asyncio.wait_for(..., timeout=10)&lt;/code&gt; as a safety net. After both halves, the same &lt;code&gt;reboot&lt;/code&gt; drops from 90 seconds to one second.&lt;/p&gt;&#xA;&lt;/blockquote&gt;</description>
    </item>
  </channel>
</rss>
