@open-matrix/runtime-hosting (0.1.19)
Installation
@open-matrix:registry=npm install @open-matrix/runtime-hosting@0.1.19"@open-matrix/runtime-hosting": "0.1.19"About this package
@open-matrix/runtime-hosting
Adapters between the generic application host and Matrix runtime/actor
lifecycles. The package has no compile-time dependency on @open-matrix/core;
its structural ports prevent a dependency cycle and keep the actor kernel
hosting-independent.
Runtime ownership
Generic Host
-> MatrixRuntimeHostedService
-> MatrixRuntime lifecycle
-> MatrixActorLease lifecycle
AddLegacyMatrixRuntime() is an explicitly named Anti-Corruption Layer for the
current constructor-starting runtime. It preserves inert host Build() by
deferring runtime construction until host startup, but it does not make the
legacy constructor itself inert.
If an asynchronous legacy factory ignores cancellation and returns after the
startup deadline, the adapter compensates the unexposed result by invoking its
shutdown() operation and then asynchronous disposal. The canceled result is
never published through IMatrixRuntimeAccessor; cleanup failures remain
observable and retain the runtime as host-disposal retry authority.
AddNativeMatrixRuntime() is the target path:
const builder = Host.CreateApplicationBuilder();
AddMatrixActorActivation(builder.Services);
AddNativeMatrixRuntime(
builder.Services,
(services, token) => {
token.ThrowIfCancellationRequested();
return MatrixRuntimeBuilder.create()
.withTransport(transport)
.withActorActivator(
services.GetRequiredService(IMatrixActorActivatorKey),
)
.buildInert();
},
);
await using host = builder.Build();
await host.StartAsync();
The native adapter maps:
Host StartingAsync -> construct inert runtime + ValidateAsync
Host StartAsync -> runtime StartAsync
Host StoppingAsync -> runtime BeginDrainAsync
Host StopAsync -> runtime StopAsync
Provider disposal -> runtime DisposeAsync
Runtime stop is a retryable resource transaction. A failed or caller-canceled
StopAsync attempt leaves the lifecycle nonterminal, retains the exact runtime,
and clears only the failed in-flight attempt. A later host stop supplies a fresh
cancellation signal and resumes at runtime stop without repeating a completed
drain phase. The runtime is published by IMatrixRuntimeAccessor only while its
state is operational or successfully stopped; a faulted-but-retained runtime is
kept private as cleanup authority until retry succeeds or disposal completes.
Hosted resources
AddHostedResource() adapts one independently owned asynchronous resource into
an IHostedLifecycleService. Registration order expresses dependency order:
resources start dependencies-first and stop consumers-first. Construction and
asynchronous I/O occur during host startup rather than in dependency-injection
factories.
Hosted-resource shutdown is also a retryable resource transaction. A failed or
caller-canceled StopAsync attempt:
- retains the exact resource value as cleanup authority;
- transitions the accessor to
Faulted, so operational access is refused while cleanup remains incomplete; - discards only the failed in-flight stop promise;
- accepts a fresh cancellation token on the next host stop;
- does not repeat a successfully completed
BeginDrainAsyncphase; - disposes and releases the value only after stop succeeds.
DisposeAsync() cannot destroy the retained object graph while stop remains
incomplete. It first resumes the stop transaction with CancellationToken.None;
only successful stop permits final resource disposal and the terminal
Disposed state.
Actor activation
AddMatrixActorActivation() registers a service-provider-backed actor
activator. Activation is two-phase so the runtime can wire RootActor control
delegates before inbox subscriptions begin:
const lease = await activator.CreateLeaseAsync(
ActorType,
context,
id,
properties,
);
// Runtime-owned callbacks and metadata are installed here.
await lease.InitializeAsync(signal);
Each lease owns one actor and one asynchronous dependency scope. It guarantees:
- initialization at most once;
- disposal at most once;
- actor disposal before scope disposal;
- cleanup after failed initialization;
- a fresh scope for every supervised restart;
- disposal requests abort cancellation-aware initialization and then join the single in-flight initialization transaction before releasing either resource;
- cancellation-unaware initialization is still serialized: any allocation made after an awaited continuation is observed before actor disposal begins, so no actor can resume into an already-disposed dependency scope;
- the post-initialization cancellation fence prevents a lease from publishing
IsInitialized = trueafter disposal has been requested.
Important tradeoffs
MatrixContextremains hierarchical actor/protocol context; the dependency scope is a separate flat lifetime boundary.- Existing property-bag actors continue through
ActorPropertyBinderwhile implementation dependencies move toward constructor injection. - Dynamic packages may not mutate the root provider after build; package-local providers are a later package-hosting concern.
- The legacy adapter is temporary and must not become an unnamed fallback.
Dependencies
Dependencies
| ID | Version |
|---|---|
| @open-matrix/core | 0.1.31 |
| @open-matrix/hosting | 0.1.7 |
Development Dependencies
| ID | Version |
|---|---|
| @types/node | ^25.0.10 |
| typescript | ^5.7.0 |