Skip to content

Adapter Lifecycle

Every adapter in the OpenFrame ecosystem follows the same four-phase lifecycle: connect, health check, execute, close.


Lifecycle Phases

stateDiagram-v2
    direction LR
    [*] --> Connecting : adapter constructed
    Connecting --> Ready : connection pool established
    Connecting --> Failed : AdapterConnectionError
    Ready --> Checking : is_ready() on startup
    Checking --> Serving : is_ready() returns True
    Checking --> Failed : is_ready() returns False
    Serving --> Serving : execute operations
    Serving --> Reconnecting : driver detects connection loss
    Reconnecting --> Serving : pool replaces connection
    Reconnecting --> Failed : reconnect exhausted
    Serving --> Closed : adapter.close() on shutdown
    Failed --> [*]
    Closed --> [*]

Reconnect Safety

When a connection pool replaces a broken connection, the driver may replace its own internal method objects. TracingProxy is designed for this — it resolves the method via getattr(wrapped, name) on every async call, never from a snapshot captured at first access.

async def _traced(*args, **kwargs):
    # Re-resolves on every call — never a stale snapshot
    current = getattr(object.__getattribute__(self, "_wrapped"), name)
    with get_tracer().start_as_current_span(f"{prefix}.{name}"):
        return await current(*args, **kwargs)

→ See tracing flow for the full span creation sequence.


Health Check Contract

HealthCheck.ping() must never raise — return False on any failure. HealthCheck.is_ready() has the same contract. This is enforced by convention; the Protocol does not enforce it at the type level.

async def ping(self) -> bool:
    try:
        await self._pool.fetchval("SELECT 1")
        return True
    except Exception:
        return False  # never raise

→ See health module for the full Protocol definition.