This release is a pre-release and may not be stable for production use.
Aeterna Runtime
aeterna-runtime composes Aeterna configuration and dependency injection into an
application lifecycle. It supports embedded use in an existing event loop and standalone
hosting that owns the event loop and handles termination signals.
Features
- Build configuration, services, lifecycle hooks, and hosted services together.
- Run hooks in registration order on startup and reverse order on shutdown.
- Supervise hosted-service tasks, propagate unexpected completion or failure, and request cooperative cancellation during shutdown.
- Close the service provider during shutdown and enforce a configurable graceful-shutdown timeout.
- Use
run()for framework-owned event-loop and signal handling, or build/start/wait/stop from an embedding framework's event loop. - Emit runtime debug logging only when the consuming application configures logging.
Requirements
- Python 3.12 or later.
aeterna-configandaeterna-di.
The Aeterna dependencies are installed automatically with this package.
Installation
With pip:
pip install aeterna-runtime
With uv:
uv add aeterna-runtime
Basic usage
run() builds the application and owns the event loop. The configuration snapshot and
cancellation token are registered as services before the provider is built.
from aeterna.config import Configuration, MappingProvider
from aeterna.di import ServiceLifetime
from aeterna.runtime import ApplicationBuilder, ApplicationContext, run
class Greeter:
def __init__(self, configuration: Configuration) -> None:
self._greeting = configuration.require("greeting")
def message(self) -> str:
return str(self._greeting)
builder = ApplicationBuilder().add_configuration(MappingProvider({"greeting": "hello"}))
builder.configure_services(
lambda services, _: services.add_type(Greeter, lifetime=ServiceLifetime.SINGLETON)
)
async def main(context: ApplicationContext) -> str:
return (await context.services.get(Greeter)).message()
print(run(builder, main)) # hello
Lifecycle and integration details
Use add_configuration() to add a ConfigurationProvider, configure_services() to
register services after configuration has loaded, and add_lifecycle_hook() to register
synchronous or asynchronous start and stop callbacks. add_hosted_service() registers a
singleton implementing HostedService, whose start(), run(), and stop() methods
receive an ApplicationContext.
The normal state sequence is CREATED, STARTING, RUNNING, STOPPING, then STOPPED;
failures enter FAILED. Application code can read context.state, but state changes are
runtime-owned. A hosted service's run() method should continue until its cancellation
token is cancelled or it fails. Shutdown requests cancellation, stops services and hooks in
reverse order, waits for running tasks, then closes the provider. The default timeout is
30 seconds and use_shutdown_timeout() configures it.
Application.run(main=None) is the standalone convenience API: it owns the event loop, builds
the application, starts hooks and hosted services, supervises execution, and stops the application.
For embedding, await ApplicationBuilder.build() and then call Application.start() from the
caller's event loop. Await Application.wait() while the surrounding server is running so
unexpected hosted-service completion is surfaced and cleaned up. Normal cancellation returns
from wait(); the host should still call Application.stop() in its shutdown path.
Embedded hosts own their own signals and server lifecycle. run() owns the loop via
asyncio.run and temporarily maps SIGINT/SIGTERM to cooperative cancellation where
supported.
exit_code() maps successful completion to 0, cancellation or KeyboardInterrupt to
130, and other errors to 1; it is only a mapping helper and is not called by run().
Public API
Classes, protocols, and enum:
ApplicationBuilder: configures and asynchronously builds an application.Application: built application with asynchronousstart(),wait(),run(), andstop().Application.start(): start hooks and hosted services and schedule their run tasks.Application.wait(): supervise hosted services for embedded hosts until cancellation or unexpected completion.Application.stop(): request cancellation, clean up started components, and close owned resources.ApplicationContext: services, configuration, cancellation, and current state for callbacks.ApplicationState:CREATED,STARTING,RUNNING,STOPPING,STOPPED, andFAILED.CancellationToken: cooperative cancellation signal withcancel(),wait(), andis_cancelled.HostedService: protocol defining asynchronousstart(),run(), andstop().LifecycleHook: pair of startup and shutdown callbacks.
Functions:
run(builder, main=None): build and run an application with a framework-owned loop.exit_code(error): return a process exit code for a completion error.
Exceptions:
ApplicationError: base class for runtime failures.ApplicationCancellationError: cleanup could not complete normally after cancellation.InvalidStateError: a lifecycle operation is invalid in the current state.StartupError: startup failed.HostedServiceError: a hosted service stopped unexpectedly.ShutdownTimeoutError: graceful shutdown exceeded its deadline.
Tests
From the repository root:
uv sync --locked
uv run pytest tests/test_runtime.py tests/test_hosting.py
Release files for aeterna-runtime 1.0.0.dev1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| aeterna_runtime-1.0.0.dev1.tar.gz | 11.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aeterna_runtime-1.0.0.dev1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 23.9 kB
Release files / aeterna_runtime-1.0.0.dev1.tar.gz
| Download URL | aeterna_runtime-1.0.0.dev1.tar.gz |
|---|---|
| Size | 11.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
814ebce079bc8f0a56c4cf48aa3b82972a6ce2a15abe7d5ed4113342d8651779
|
|
BLAKE2b-256 checksum How to use checksums |
16c7c7914a754443746be88ff8307ff8135c3a045ef053c46cd85263307ef0a4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.
Transparency logRelease files / aeterna_runtime-1.0.0.dev1-py3-none-any.whl
| Download URL | aeterna_runtime-1.0.0.dev1-py3-none-any.whl |
|---|---|
| Size | 12.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0dc58162abfce092d7b7e5756f290967ba610e5d8379034ddadd02a65ee76fa1
|
|
BLAKE2b-256 checksum How to use checksums |
b5849f4489c3acbec2c65d74032bdc94021c3c7eff5012897c712037976cc215
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 20, 2026.
Transparency log