← Toutes les actualités
ops-basics4 min de lecture

Your AI Assistant Forgot the Shutdown Signal

Par Seaworthy · 20 octobre 2026

Networking equipment with ethernet cables connected in a server rack

Photo by Albert Stoynov on Unsplash

A few weeks ago I watched a team deploy a service that had been almost entirely scaffolded by an AI coding assistant. The code was clean. Tests passed. The deploy went out, and within minutes the error dashboard lit up with 502s and a handful of half-written database rows. The cause was not exotic. The process had no graceful shutdown handling at all. SIGTERM arrived, the runtime exited immediately, in-flight requests died mid-response, and background writes were abandoned.

This is a familiar pattern now. AI assistants are very good at producing the happy path: start the server, wire the routes, connect the database. They are much less reliable at producing the boring operational seams that only matter when things go wrong. Graceful shutdown is one of those seams. If you accept generated code without asking about it, you inherit the gap.

What actually happens without it

When your orchestrator decides to stop a pod or your init system stops a service, it sends a termination signal (usually SIGTERM). A process without a handler dies on the spot. Anything in progress is lost: HTTP responses cut off, queue messages acknowledged but not processed, file writes truncated, connections dropped without a clean close. Clients see errors. Upstream services see resets. Your logs show a clean exit, which makes the incident harder to diagnose because nothing looks wrong from the inside.

The damage compounds during rolling deploys. Every instance termination becomes a small outage. Under load, that is a steady drip of failed requests that your retries may mask until they don't.

The pattern the assistant usually gives you

Generated servers tend to look like this. It runs, and it is wrong the moment the process is asked to stop.

from http.server import BaseHTTPRequestHandler, HTTPServer

class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        body = self.rfile.read(int(self.headers['Content-Length']))
        process_payment(body)  # long-running work
        self.send_response(200)
        self.end_headers()

# No signal handling. SIGTERM kills the process mid-request.
HTTPServer(('0.0.0.0', 8080), Handler).serve_forever()

Nothing here is malicious or even unusual. It is just incomplete. The assistant optimized for a working demo, and a working demo does not get terminated.

What the fix looks like

The shape of graceful shutdown is consistent across languages: catch the signal, stop accepting new work, let in-flight work finish within a deadline, then exit. Here is the same service with that seam added.

import signal
import threading
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

shutdown_event = threading.Event()

class Handler(BaseHTTPRequestHandler):
    def do_POST(self):
        body = self.rfile.read(int(self.headers['Content-Length']))
        process_payment(body)
        self.send_response(200)
        self.end_headers()

server = ThreadingHTTPServer(('0.0.0.0', 8080), Handler)

def handle_sigterm(signum, frame):
    shutdown_event.set()
    # Stop accepting new connections; existing requests finish.
    threading.Thread(target=server.shutdown, daemon=True).start()

signal.signal(signal.SIGTERM, handle_sigterm)

server.serve_forever()
shutdown_event.wait(timeout=30)
server.server_close()

The details vary by framework and language, but the questions do not: does the signal get caught, do new requests stop arriving, and is there a bounded deadline so a stuck request cannot block the exit forever? Your orchestrator's termination grace period must be longer than that deadline, or the platform will kill you anyway.

Why this keeps slipping through

AI assistants reflect the distribution of code they were trained on. Startup code is everywhere. Shutdown code is sparse, often wrong, and rarely covered by the examples that make it into tutorials. When you prompt for a service, you get the parts that are easy to demonstrate. The operational edges are the parts nobody demonstrates.

That means the review burden falls on you. I think that is fine, but only if you actually carry it. Treat generated server code as a draft, and ask explicit operational questions before merging: what happens on SIGTERM, what is the drain timeout, what happens to queued work, and how is the readiness endpoint tied to the shutdown state. If the assistant cannot answer, the code is not ready.

A useful habit is to add a shutdown test to your suite. Send the signal, assert that in-flight requests complete and that new connections are refused. It is a small test that catches a large class of deploy-time failures.

The uncomfortable part

Most of the incidents I see from AI-generated services are not clever security bugs. They are missing basics. Graceful shutdown is one of the cheapest basics to add and one of the easiest to forget when the code arrives looking finished. Do not let a passing demo convince you the operational seams are in place. Check them, or they will check you during your next deploy.

Seaworthy reviews generated service code for operational gaps like missing shutdown handling, with a focus on the basics that demos skip.

Cet article a été généré par IA et résume des sources publiquement disponibles.

Par les créateurs de Seaworthy

Seaworthy analyse votre dépôt pour détecter les problèmes abordés dans des articles comme celui-ci.

Failles de sécurité, secrets exposés et mauvaises configurations détectés avant le déploiement. Gratuit, aucun compte requis.

$ npx seaworthycode