Skip to content

Reconcile

Reconciliation syncs the server's database with the actual state of running containers. It is the fix for situations where the sandbox count in the database is out of sync with what Docker reports - for example, after a host reboot, a crash, or a manual docker rm.

The server reconciles on its own in three situations:

TriggerWhen
StartupOnce at boot, before accepting traffic, if AUTO_RECONCILE=true (the default).
Periodic loopEvery reconcile interval (default 30 s) while the server is running.
Docker eventsWhenever a container exits or is destroyed, the event monitor updates the affected sandbox immediately.

For most deployments automatic reconciliation is sufficient. The manual API is useful when you need the database to reflect reality right now - for example, immediately after clearing stuck containers so a new sandbox creation can succeed.

For every sandbox row in the database, the server checks whether a matching Docker container exists:

  • Container missing - the sandbox is marked destroyed, its Caddy routes are removed, and any mounts are unmounted.
  • Container present - the sandbox's status, IP address, and Caddy routes are refreshed to match the live container state.

Rows that were already destroyed before the pass are left unchanged.

await client.reconcile()

The call blocks until the full reconcile pass completes. On success it returns with no data. On failure it throws with the server-side error message.

Common scenario: capacity exceeded after a restart

Section titled “Common scenario: capacity exceeded after a restart”

If the host was rebooted or containers were removed outside of the API, the database still counts those sandboxes against the CPU and memory budget. Creating a new sandbox fails with host capacity exceeded.

Fix:

// Force the DB to reflect what Docker actually sees
await client.reconcile()
// Now create succeeds
const sandbox = await client.create({ image: 'ubuntu:22.04' })