python
41 lines · 7 steps
Graceful shutdown in a queue worker
A worker loop that catches termination signals and exits only after the current task finishes.
Explained by
highlit
1import signal
2import time
3import logging
4
5logger = logging.getLogger("worker")
6
7
8class GracefulWorker:
9 def __init__(self, queue, poll_interval=1.0, visibility_timeout=30):
10 self.queue = queue
11 self.poll_interval = poll_interval
12 self.visibility_timeout = visibility_timeout
13 self._shutdown = False
14
15 def _request_shutdown(self, signum, frame):
16 logger.info("received signal %s, finishing current task then exiting", signum)
17 self._shutdown = True
18
19 def run(self):
20 signal.signal(signal.SIGTERM, self._request_shutdown)
21 signal.signal(signal.SIGINT, self._request_shutdown)
22
23 while not self._shutdown:
24 message = self.queue.receive(wait_seconds=self.poll_interval)
25 if message is None:
26 continue
27 self._process(message)
28
29 logger.info("worker stopped cleanly")
30
31 def _process(self, message):
32 try:
33 self.handle(message.body)
34 except Exception:
35 logger.exception("task %s failed, leaving for redelivery", message.id)
36 self.queue.release(message)
37 else:
38 self.queue.ack(message)
39
40 def handle(self, body):
41 raise NotImplementedError
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A shared flag lets a signal handler request shutdown without interrupting work mid-task.
- 2Acknowledge messages only on success so failures are redelivered instead of silently lost.
- 3Leaving handle unimplemented turns the class into a reusable base for concrete workers.
Related explainers
python
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, status from pydantic import BaseModel, EmailStr from sqlalchemy.orm import Session
Building a signup endpoint in FastAPI
dependency-injection
request-validation
background-tasks
Intermediate
8 steps
rust
use axum::{extract::{Path, State}, http::StatusCode, Json}; use dashmap::DashMap; use serde::Serialize; use std::sync::Arc;
Request coalescing in an Axum handler
caching
concurrency
request-coalescing
Advanced
8 steps
ruby
class TemplateInterpolator PLACEHOLDER = /\{\{\s*([\w.]+)\s*\}\}/ def initialize(strict: false)
Interpolating templates with dotted keys in Ruby
regex
string-interpolation
hash-traversal
Intermediate
6 steps
python
from django import forms from django.utils import timezone from .models import Reservation
Multi-field validation in a Django ModelForm
form validation
cross-field validation
modelform
Intermediate
7 steps
python
from django import template from django.urls import reverse, NoReverseMatch from django.utils.html import format_html
Active nav-link template tags in Django
template tags
url routing
active state
Intermediate
7 steps
go
package config import ( "fmt"
A thread-safe config singleton in Go
singleton
concurrency
environment-variables
Intermediate
7 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/graceful-shutdown-in-a-queue-worker-explained-python-928f/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.