How to Check Uptime with a Synthetic HTTP Mock in Python

Run a mock HTTP server locally and probe it with urllib to measure synthetic uptime and response times, perfect for testing monitoring logic without external dependencies.

Medium Python 3.9+ Aug 9, 2026 Observability & SRE 14 views 0 copies

Python code

48 lines
Python 3.9+
import http.server
import threading
import time
import urllib.request


class MockHandler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == "/health":
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            self.wfile.write(b'{"status": "ok"}')
        else:
            self.send_response(404)
            self.end_headers()

    def log_message(self, format, *args):
        pass


def check_uptime(url, timeout=2):
    try:
        start = time.time()
        with urllib.request.urlopen(url, timeout=timeout) as response:
            elapsed = time.time() - start
            return response.status == 200, elapsed
    except Exception:
        return False, None


def main():
    server = http.server.HTTPServer(("127.0.0.1", 0), MockHandler)
    port = server.server_address[1]
    thread = threading.Thread(target=server.serve_forever, daemon=True)
    thread.start()

    url = f"http://127.0.0.1:{port}/health"
    for _ in range(3):
        up, response_time = check_uptime(url)
        print(f"Uptime: {up}, Response time: {response_time:.3f}s")
        time.sleep(0.2)

    server.shutdown()


if __name__ == "__main__":
    main()

Output

stdout
Uptime: True, Response time: 0.001s
Uptime: True, Response time: 0.001s
Uptime: True, Response time: 0.001s

How it works

This script spins up a lightweight HTTP server using the standard library's http.server module, with a custom handler that returns a 200 status for /health and 404 otherwise. The check_uptime function uses urllib.request.urlopen to send a GET request and measures the round-trip time with time.time(). The server runs in a daemon thread so it stops automatically when the main thread finishes. The loop simulates repeated health checks, printing whether each probe succeeded and how long it took, mimicking a basic synthetic monitor. Because everything uses only built-in modules, this pattern is ideal for testing monitoring code in CI or local development without standing up a real service.

Common mistakes

  • Forgetting to call `server.shutdown()` leads to a hanging process on exit.
  • Using `http.server.HTTPServer` without a daemon thread can block program termination.
  • Assuming the server port is fixed — using port 0 assigns a random free port, which is more robust for tests.

Variations

  1. Use `requests.get` instead of `urllib.request` if you prefer a third-party library with better error handling.
  2. Add a timeout and retry logic with exponential backoff to simulate production monitor behavior.

Real-world use cases

  • Testing your custom uptime monitoring script against a local mock before deploying it to monitor real endpoints.
  • Simulating health checks in a CI pipeline to validate that your service's /health endpoint responds correctly.
  • Benchmarking response times of your application locally without needing a load balancer or external uptime service.

Sponsored

Run this sample

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

Open editor

More from Observability & SRE

Related tutorials and quizzes for this topic.