How to Mock a 202 Accepted Long-Running Operation in Python

Build a mock HTTP server that returns a 202 Accepted response immediately and simulates a long-running operation in the background with threading.

Medium Python 3.9+ Aug 9, 2026 API design & gRPC 13 views 0 copies

Python code

30 lines
Python 3.9+
import time
import threading
from http.server import HTTPServer, BaseHTTPRequestHandler

class MockHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        if self.path == "/long-running":
            self.send_response(202)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            self.wfile.write(b'{"status": "accepted", "job_id": "12345"}')
            
            # Simulate long-running work in background
            threading.Thread(target=self._process, daemon=True).start()
    
    def _process(self):
        time.sleep(3)  # Simulate 3-second operation
        print("Long-running operation completed")
    
    def log_message(self, format, *args):
        pass  # Silence default logging

def run():
    server = HTTPServer(("127.0.0.1", 8000), MockHandler)
    print("Mock server running on http://127.0.0.1:8000")
    print("POST /long-running returns 202 Accepted immediately")
    server.serve_forever()

if __name__ == "__main__":
    run()

Output

stdout
Mock server running on http://127.0.0.1:8000
POST /long-running returns 202 Accepted immediately
Long-running operation completed

How it works

The do_POST method checks the request path and returns a 202 Accepted status with a JSON body immediately. A background thread is started using threading.Thread with daemon=True so it does not block the server. The time.sleep(3) call simulates real work, and the completion message appears on the server console, not in the HTTP response. Silencing log_message keeps the mock server's output clean for debugging.

Common mistakes

  • Blocking the request handler with `time.sleep` before returning the response, which defeats the purpose of 202
  • Forgetting to set `daemon=True` on the background thread, preventing the server from shutting down cleanly
  • Trying to include the long-running result in the same HTTP response instead of returning it in a separate status endpoint

Variations

  1. Use `concurrent.futures.ThreadPoolExecutor` to manage multiple background jobs instead of raw threads
  2. Add a separate `GET /status/{job_id}` endpoint so clients can poll for completion

Real-world use cases

  • Mocking an async job queue during integration testing of API clients that expect 202 patterns.
  • Simulating a report generation service where the API acknowledges the request and processes it in the background.
  • Creating a fake webhook receiver that accepts events instantly for load testing consumer pipelines.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from API design & gRPC

Related tutorials and quizzes for this topic.