---
myst:
  html_meta:
    'description': 'How the ABR SDK manages object lifetimes: the context manager pattern, close(), and how child resources are cleaned up.'
    'keywords': 'sdk lifecycle, close, context manager, resource management, application, asr, tts'
---

# SDK lifecycle

Every ABR SDK object wraps a native handle. Releasing that handle correctly is the caller's
responsibility. This page explains how object lifetimes work, why the `with` block is the
recommended pattern, and what happens to child resources when a parent is closed.

## Application and its subclasses

{py:class}`~abr_sdk.core.Application` is the base class for all ABR runtime objects. When you use
ASR, you create an {py:class}`~abr_sdk.asr.Asr` instance; when you use TTS, you create a
{py:class}`~abr_sdk.tts.Tts` instance. Both inherit from {py:class}`~abr_sdk.core.Application`.

You rarely interact with {py:class}`~abr_sdk.core.Application` directly. Its lifecycle methods
({py:meth}`~abr_sdk.core.Application.close` and
{py:meth}`~abr_sdk.core.Application.create_event_set`) are inherited by {py:class}`~abr_sdk.asr.Asr`
and {py:class}`~abr_sdk.tts.Tts` and behave the same way on any instance.

## The context manager pattern

The recommended way to use any ABR object is inside a `with` block:

```python title="recommended.py"
from abr_sdk.asr import Asr

with Asr("/path/to/libniagara_38m_live.so") as asr:
    # use asr here
    ...
# close() is called here, whether the block exits normally or raises
```

When the `with` block exits, Python calls {py:meth}`~abr_sdk.core.Application.__exit__`, which calls
{py:meth}`~abr_sdk.core.Application.close`. This happens on both normal exit and on exceptions. The
`with` block is the safest pattern because cleanup is guaranteed even if your code raises partway
through. The same applies to {py:class}`~abr_sdk.tts.Tts`; use a `with` block and
{py:meth}`~abr_sdk.core.Application.close` is called automatically on exit.

## What {py:meth}`~abr_sdk.core.Application.close` does

{py:meth}`~abr_sdk.core.Application.close` releases the native handle and all child resources. The
sequence is the same for {py:class}`~abr_sdk.asr.Asr` and {py:class}`~abr_sdk.tts.Tts`:

1. Any in-progress session is closed.
2. All {py:class}`~abr_sdk.core.EventSet` objects owned by the application are closed, which closes
   their associated {py:class}`~abr_sdk.core.Event` objects.
3. The native application handle is freed.

After {py:meth}`~abr_sdk.core.Application.close` returns, calling any method on the object raises
`RuntimeError`. Calling {py:meth}`~abr_sdk.core.Application.close` a second time has no effect.

## Explicit {py:meth}`~abr_sdk.core.Application.close`

When a context manager is not practical, for example when an {py:class}`~abr_sdk.asr.Asr` or
{py:class}`~abr_sdk.tts.Tts` instance is owned by a longer-lived class, call
{py:meth}`~abr_sdk.core.Application.close` explicitly:

```python title="explicit_close.py"
from abr_sdk.asr import Asr

class Transcriber:
    def __init__(self, library_path: str) -> None:
        self._asr = Asr(library_path)

    def transcribe(self, audio: bytes) -> str:
        return self._asr.process(audio).text

    def shutdown(self) -> None:
        self._asr.close()
```

Call {py:meth}`~abr_sdk.core.Application.close` before the object goes out of scope. If
{py:meth}`~abr_sdk.core.Application.close` is never called, the native handle will not be freed
until the process exits. The same pattern applies to {py:class}`~abr_sdk.tts.Tts`.

:::{admonition} Next steps
:class: hint

- {doc}`/concepts/streaming-and-chunks`: how {py:class}`~abr_sdk.core.EventSet`,
  {py:class}`~abr_sdk.core.Event`, and {py:class}`~abr_sdk.core.Buffer` work together underneath the
  high-level API.
- {py:class}`~abr_sdk.asr.Asr`: full method reference for
  {py:meth}`~abr_sdk.core.Application.close`, {py:meth}`~abr_sdk.asr.Asr.push`, and
  {py:meth}`~abr_sdk.asr.Asr.wait_for_completion`.
- {py:class}`~abr_sdk.tts.Tts`: full method reference for {py:meth}`~abr_sdk.core.Application.close`
  and TTS synthesis methods.
  :::
