Dev.to AI 🤖 Ai 👁 0 📖 7 min read

Keep Health Probes Off the Model on a Free Host

A free host probes and restarts. The health route has to answer from local memory, with no model call and no disk state. That split is what lets a solo founder ship one route today and keep the bill at zero. An AI draft

A free host probes and restarts. The health route has to answer from local memory, with no model call and no disk state. That split is what lets a solo founder ship one route today and keep the bill at zero.

An AI draft often does the opposite. It puts a "model is reachable" check inside /health, adds a retry, and stores the last success in a global. The chat result looks careful. On a free server the probe runs far more often than any user request, and a restart wipes the global so the next probe fails or calls out again.

Model quality and host constraints are different problems. A sharper draft can still put a network call on the probe path. The host will not forgive that just because the draft read well in a chat window. The workflow below refuses that shape before the host starts.

The rule, in one table

The table is a local policy. It is not a vendor quota and it is not a benchmark.

Check Ship Stop
Health body Fixed JSON from memory Any fetch, SDK call, or retry
Imports in health.py No network or model-SDK imports socket, urllib, requests, httpx, or a model SDK
State No file and no global required for a 200 Token caches, lock files, last-probe timestamps
Restart drill Same body after kill and start Different body, hang, or a new dependency
Model use One draft of the business route, off the probe path A model call inside the probe or on import

Tighten the table if the host is smaller. Do not loosen it so the probe can "just verify" the assistant.

Step 1: Put the probe in its own module

Create health.py before asking any model to draft the business route. The probe module stays hand-written. The model may touch route.py later. It does not get to edit health.py.

"""Probe handler. Unexecuted example: review before running."""

def health() -> dict:
    return {"ok": True, "deps": "none"}

Three fields would already be too many if one of them required a lookup. ok says the process is up. deps records that this ship has none.

A future route can grow. This file should not.

What the model may change

Allowed changes sit in route.py and nowhere else.

  1. A single handler for one business path.
  2. Pure functions that take arguments and return values, with no client construction.
  3. Comments that restate the frozen probe rule.

Forbidden changes are a stop, even when the code compiles.

  1. Any edit to health.py or scan_health_imports.py.
  2. A retry, a sleep loop, or a helper whose job is to ping a model.
  3. A new file whose name contains worker, queue, or cron.
  4. A README line that tells the founder to add a database so the probe can look complete.

That list is the review. It takes less time than reading a generated diff that has no boundary.

Step 2: Fail the build when the probe grows a client

A source scan is blunt and useful. It reads health.py as syntax and rejects network imports. The usual generated patch adds a normal import at the top of the file, and this scan catches that shape.

Dynamic imports can slip through. That hole is listed under limits. Do not treat a green scan as a proof of isolation.

"""Import boundary for health.py. Unexecuted example."""

import ast
import pathlib
import sys

BANNED = {"socket", "urllib", "requests", "httpx", "model_sdk"}

def main() -> int:
    tree = ast.parse(pathlib.Path("health.py").read_text(encoding="utf-8"))
    bad = []
    for node in ast.walk(tree):
        if isinstance(node, ast.Import):
            names = [alias.name for alias in node.names]
        elif isinstance(node, ast.ImportFrom) and node.module:
            names = [node.module]
        else:
            continue
        for name in names:
            if name.split(".")[0] in BANNED:
                bad.append(name)
    if bad:
        print("banned imports: " + ", ".join(bad))
        return 1
    print("health imports ok")
    return 0

if __name__ == "__main__":
    raise SystemExit(main())

Replace model_sdk with the import root of whatever client the draft actually used. The placeholder is not a product name.

python3 scan_health_imports.py

A nonzero exit stops the ship. Do not add the banned name to an allow list in the same hour the draft suggested it. That is the patch asking for a second design.

Step 3: Assert that a call does not touch the network

The scan cannot see a helper, imported from route.py, that opens a socket. A tiny test covers the runtime path. The example expects pytest and monkeypatch. It stays an unexecuted example until it runs in a clean virtualenv.

"""Runtime boundary. Unexecuted example."""

import socket
import urllib.request

import health

def test_health_makes_no_network(monkeypatch):
    def boom(*_args, **_kwargs):
        raise AssertionError("health opened the network")

    monkeypatch.setattr(socket, "socket", boom)
    monkeypatch.setattr(urllib.request, "urlopen", boom)
    assert health.health() == {"ok": True, "deps": "none"}
python3 -m pytest -q test_health.py

The assertion is the contract. If a later edit needs a database check before it can return 200, this test should fail and the ship should wait. A solo free host is the wrong place to invent a dependency probe.

Step 4: Kill the process and demand the same body

Free hosts restart. Some sleep when traffic stops. This draft claims neither a sleep timer nor a memory cap nor an uptime figure, because none of those were measured here. The local drill proves a weaker fact: the probe does not need a global that the process just lost.

"""Local probe server. Unexecuted example."""

import json
from http.server import BaseHTTPRequestHandler, HTTPServer

import health

class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path != "/health":
            self.send_response(404)
            self.end_headers()
            return
        body = json.dumps(health.health()).encode()
        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

    def log_message(self, *_args):
        return

if __name__ == "__main__":
    HTTPServer(("127.0.0.1", 8080), Handler).serve_forever()
python3 probe_server.py &
PID=$!
sleep 0.3
curl -fsS --max-time 2 http://127.0.0.1:8080/health > /tmp/h1.json
kill "$PID"
wait "$PID" 2>/dev/null || true
python3 probe_server.py &
PID=$!
sleep 0.3
curl -fsS --max-time 2 http://127.0.0.1:8080/health > /tmp/h2.json
kill "$PID"
cmp /tmp/h1.json /tmp/h2.json

cmp is the promotion check. A mismatch means the route rebuilt state, called something, or changed shape across a restart. Fix that on the laptop. Do not debug it after the host has started probing.

Step 5: Read the failure, then stop

Each failed check has one repair. A second repair in the same pass usually means the design grew a new service.

Exit signal Meaning Next action
Scan exit 1 health.py imported a banned root Delete the import. Do not wrap it in a helper
Pytest failure health() reached socket or urlopen Remove the call. The monkeypatch is doing its job
Curl timeout Nothing accepted connections on 127.0.0.1:8080 Fix the bind. Do not raise --max-time
cmp difference The body depends on process lifetime Return the constant dict again

Write the failing signal into the commit message, then stop for the day if the repair is not the one in that row. Shipping around a red check is how a free host starts a bill.

Step 6: Use a free model on the route, never on the probe

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

The operator describes MonkeyCode as an open-source coding assistant with free model access and a free server option. Those availability claims are operator-supplied. This draft does not name a model, state a token quota, describe hardware, or treat either option as permanent.

Confirm the project page on ship day. If either claim is gone, keep the health split and skip the product. The three local commands still decide the ship.

Use the free model, when it is actually available, for one draft of route.py only. Paste a line that health.py is frozen. Discard a reply that edits the probe, adds a retry, or imports a client into the health module. Then run the scan, the test, and the restart drill again. The model does not promote the ship. The commands do.

The free server, when it is actually available, is where the already-tested process runs. Copy the probe module, the app entry, and the business route. Leave add-ons, cron, and a database toggle off.

A probe that stays local is what keeps that host from calling a model on every platform check. Point the host health setting at /health only after the local cmp succeeded.

Limits, and who should ignore this

The scan misses importlib and clients hidden behind a string. The test misses a network call that happens only when a host environment variable is set. The restart drill uses localhost and a short sleep. It does not reproduce disk quotas, TLS, or a real idle policy.

No latency number in this article is a measurement. No token total is stated, because none was verified for this draft. Founders who need a current quota should read the project page themselves and treat this workflow as the constraint, not as a pricing page.

A team whose health check must fail closed when a database is down should not adopt this probe. Their users need a dependency signal. A product that already has a paid host and a scheduler should not pretend a three-command drill is an operations platform.

This pattern is for a solo founder shipping one route, accepting a dull health body, and refusing extra moving parts until a bill is a choice. Run the scan, the test, and the restart cmp in that order. Ship only if all three pass, and leave the probe file out of the model session.

📰 Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.