Angular — advanced usage

Escape hatches past the binding layer: connectWorker tuning, per-call abort/timeout, shared observables, and pool lifecycle — same APIs under every framework's idiom.

Route-scoped pools

provideAtoll works in Route.providers — the pool spawns when the route injector is created and terminates when it is destroyed. Lazy features get lazy pools.

app.routes.tsfrontend
const routes: Routes = [{
  path: 'reports',
  providers: [
    provideAtoll({ pools: [{ name: 'incidents', client: incidents }] }),
  ],
  loadComponent: () => import('./reports.component'),
}];

Async pool declarations

registerPoolAsync/forRootAsync resolve the spec from injected deps during APP_INITIALIZER — name stays static so the ATOLL_POOL:<name> token is injectable throughout.

app.module.tsfrontend
AtollModule.registerPoolAsync({
  name: 'incidents',
  inject: [PoolConfig],
  useFactory: (config: PoolConfig) => ({
    worker: () => new Worker(
      new URL('./incidents.worker.ts', import.meta.url)),
    sharedMemory: incidentsMemory,
    poolSize: config.poolSize,
  }),
})

Testing — stub the pool token

Each pool is a plain InjectionToken (ATOLL_POOL:<name>) — override it in TestBed with a stub; the component never touches a real worker.

frontend
await TestBed.configureTestingModule({
  providers: [
    { provide: getAtollPoolToken('incidents'), useValue: stubIncidents },
  ],
}).compileComponents();

Abort & timeout per call

with() attaches RunOptions to the same client surface. A queued call drops outright; an in-flight call is orphaned — the worker finishes it and the reply is discarded.

frontend
import { TaskAbortedError, TaskTimeoutError } from '@atolljs/core';

const ac = new AbortController();
const request = this.incidents
  .with({ signal: ac.signal, timeout: 2_000 })
  .queryIncidents(query);

ac.abort();   // rejects with TaskAbortedError