> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cirron.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Lifecycle

> `flush`, `health`, `shutdown`: drain buffers and tear down.

Three small helpers that manage the profiler's runtime. You rarely
call any of them directly (`atexit` invokes `shutdown` for you on
process exit), but they're useful for tests, manual checkpoints, and
health-check endpoints.

All three are available both as module-level functions
(`ci.flush()`, `ci.health()`, `ci.shutdown()`) and as methods on a
[`Profiler`](/sdk/reference/types#profiler) handle.

## `flush`

Synchronously drain the scope stack and mark buffer to the local
spool.

```python theme={null}
def flush() -> None
```

Useful when you want trace data on disk at a known point: typically
at a test assertion or before handing off to another tool.

```python theme={null}
import cirron as ci

ci.profile()
do_work()
ci.flush()            # ./.cirron/spool/ now contains everything so far
inspect_spool()
```

`flush` blocks the calling thread until the drain is complete. It
does **not** close the root scope; `ci.profile()` stays live and
continues to accept scopes and marks.

## `health`

Snapshot of SDK internals. Never raises; safe to call from an HTTP
health check.

```python theme={null}
def health() -> dict[str, Any]
```

Returned dict:

| Key                    | Type        | What it means                                     |
| ---------------------- | ----------- | ------------------------------------------------- |
| `enabled`              | `bool`      | `False` if `ci.profile(enabled=False)` was called |
| `frameworks_installed` | `list[str]` | Which framework hooks are active                  |
| `transport`            | `str`       | `"event_stream"`, `"http"`, or `"file_only"`      |
| `scope_depth`          | `int`       | Current innermost-scope depth on this thread      |
| `mark_drop_count`      | `int`       | Marks dropped because the ring buffer was full    |
| `spool_drop_count`     | `int`       | Spool batch files dropped when the cap was hit    |
| `spool_bytes`          | `int`       | Current spool disk usage                          |
| `flush_latency_ns`     | `int`       | Most recent flush thread wake-to-done duration    |

Drop counts that climb during a run are a signal to either raise the
buffer cap (`Cirron(spool_max_bytes=...)`) or reduce the rate of
`ci.mark` calls.

## `shutdown`

Close the root scope, flush synchronously, stop the flush thread,
and clear the default singleton. Idempotent; calling it twice is a
no-op.

```python theme={null}
def shutdown() -> None
```

Normally invoked by the `atexit` handler registered during
`ci.profile()`. Call it yourself when:

* You're in a test that wants a clean state between cases.
* You're hot-reloading a module that calls `ci.profile()`.
* You want to deterministically release the flush thread and its
  file handles before a `fork()`.

```python theme={null}
import cirron as ci

def test_profiler():
    p = ci.profile()
    ...
    ci.shutdown()    # reset so the next test starts clean
```

## Signal handlers

`ci.profile()` also registers SIGTERM and SIGINT handlers that call
`shutdown()` before the default handler runs, so traces are never
lost on a `kill` or Ctrl-C.

## See also

[`ci.trace`](/sdk/reference/trace) is the read-back companion to
`flush`: it returns the current session's scope tree as text, dict,
JSON, or a DataFrame without leaving the process. It is also exposed
as `Profiler.trace()` and `Cirron.trace()`.

## Related

<CardGroup cols={3}>
  <Card title="ci.profile" icon="chart-line" href="/sdk/reference/profile">
    The entry point that starts the lifecycle these manage.
  </Card>

  <Card title="ci.trace" icon="diagram-project" href="/sdk/reference/trace">
    In-process read-back of the scope tree.
  </Card>

  <Card title="Profiler type" icon="box" href="/sdk/reference/types#profiler">
    The handle exposing the same methods on an instance.
  </Card>
</CardGroup>
