Skip to content

Pinned hosts Python objects by id: one chat, document, or user per instance. Start in one process, store the state and work that must survive a restart, then add pinboard to route requests across workers.

This page describes Pinned's Python runtime. For a JavaScript host, use the Cloudflare Durable Object tutorial.

One object per id

  • Your PinnedAPI class defines the object. A namespace and id address it, such as /threads/t1.
  • PinnedWorker(hosts={"/threads": Chat}) serves the namespace and activates an instance when a request needs it. Requests for that resident id share the same Python object.
  • The worker holds the process's hosts, state store, and optional pinboard registration.
  • Idle eviction closes the instance. A later activation constructs a new object and loads its stored trays.

A tray is a stored part of the instance, with persistent fields and an optional work queue. Ordinary Python fields last for the current instance's lifetime. Tray state lasts as long as its configured store.

Choose what survives

KeepPut it inSurvives
Temporary connections, caches, and task handlesInstance memoryThe live instance
Tray fields and queued work during local developmentMemoryStateStoreInstance eviction while the store stays alive
Tray fields and work across process restarts or worker changesA shared persistent store, such as PostgresReactivation from that store

Begin with the Python chat app, then add persistence and verify a restart. An interrupted executor needs a stored continuation and a resume path; see a crash mid-run.

One request

Pinboard keeps a placement: the worker session assigned to an instance id. Requests through pinboard reach that worker.

client
pinboard
worker
request for /threads/t1
resolve the placement in Redis
forward the request with its placement epoch
activate t1 if needed: start its lifespan and restore stored trays
respond through pinboard

With a local PinnedWorker, the request reaches the host directly. Add pinboard when instances must be placed across processes. Run the two-worker tutorial.

When heartbeats stop

A worker's lease is renewed by heartbeat acknowledgments. Its deadline limits how long that worker can accept requests under the current registration.

Lease stageRequests reaching the worker
HealthyExisting instances and new activations can serve
Unhealthy, before expiryExisting instances can serve; new activations receive 503
ExpiredAll instance requests receive 503 until the lease is renewed

Lease expiry alone leaves resident objects in memory. If registration recovers, those objects can continue; an instance claimed elsewhere is closed when registration reports the duplicate. A process crash loses its memory, and another worker restores the instance from the shared store when it acquires the placement.

Pinboard also carries the proxied request traffic. Its availability and the worker's remaining lease both matter during an outage. Timing and recovery rules: leases and heartbeats. Try an actual owner failure in the fleet tutorial.

Placement and stored data

  • Redis holds the placement directory. The state store holds tray rows.
  • A placement epoch orders owners. State-store operations from an epoch below the stored instance epoch raise FenceLost.
  • Placement includes the environment, namespace, and id. Tray row identity includes the namespace, id, tray namespace, and tray id. Use separate stores when environments require separate data.
  • In local mode, workers use epoch 0. Run one local worker per store; use pinboard to coordinate multiple workers.

Setup and failure cases: persist across restarts. Credentials between clients, pinboard, and workers: Trust.

One instance over time

Explore requests, eviction, and shutdown by instance phase
request
construct the instance, run lifespan, hydrate trays; then serve
request, lease unhealthy
503 lease unhealthy; refusing new activations
request, host draining
503 host draining; retry
request, stale or released epoch
503 stale placement epoch; retry
request, lease expired
503 lease expired; not serving
wind down (instance or host)
new activations refuse while draining
shutdown
RuntimeError on any request

This table is a reference explorer. Lifecycle options: Host, PinnedHost. Callbacks: InstanceLease.

Continue building