Polling Manager API
The Polling Manager exposes a compact API focused on keyed polling lifecycle and subscription control.
Exports
import { PollingManager, pollingManager } from '@/lib/internal/PollingManager';
import type { SubscribeOptions, SubscribeResult, PollingManagerStatus } from '@/lib/internal/PollingManager';
Constructor
new PollingManager(deps?: PollingManagerDeps)
PollingManagerDeps
type PollingManagerDeps = {
scheduler?: PollingScheduler;
documentRef?: PollingDocument;
now?: () => number;
};
scheduleroverrides timer scheduling (tests/custom runtimes)documentRefenables visibility-aware pause/resume behaviornowcontrols subscription ID timestamp source (test determinism)
If documentRef is not supplied, visibility handling is disabled.
subscribe<T>(options)
subscribe<T>(options: SubscribeOptions<T>): SubscribeResult<T>
SubscribeOptions<T>
type SubscribeOptions<T> = {
key: string;
intervalMs: number;
pollFn: () => Promise<T>;
onResult: (result: T) => void;
onError?: (error: unknown) => void;
shouldStop?: (result: T) => boolean;
pauseWhenHidden?: boolean;
};
SubscribeResult<T>
type SubscribeResult<T> = {
subscriptionId: string;
unsubscribe: () => void;
update: (updates: { onResult?: (result: T) => void; onError?: (error: unknown) => void }) => void;
};
Subscription semantics
- First subscriber for a key triggers immediate poll (no deferred-first-tick mode)
- Later same-key subscribers attach only (no extra immediate poll)
- Same key dedups to one task/timer across subscribers
updateonly changes callbacks; task-defining fields are immutable- Public ID-based unsubscribe is intentionally not exposed
- Same-key task-definition mismatch fails fast (
pollFn,intervalMs,shouldStop,pauseWhenHidden)
pause and resume
pause(options?: { key?: string }): void
resume(options?: { key?: string }): void
- No args: apply globally
- With
key: apply to one task - Visibility pause takes precedence while document is hidden; global
resume()does not override hidden-state pause forpauseWhenHiddentasks
getStatus
getStatus(): PollingManagerStatus
type PollingManagerStatus = {
status: 'idle' | 'running' | 'paused';
taskCount: number;
subscriptionCount: number;
tasks: Array<{
key: string;
status: 'idle' | 'running' | 'paused';
subscriptionCount: number;
inFlight: boolean;
pauseWhenHidden: boolean;
}>;
};
stopAll
stopAll(): void
Stops all active tasks and clears subscriptions.
v1 Behavior Contract
- Immediate first poll on every new subscription
- In-flight overlap protection (skip interval tick while current poll is pending)
- Terminal auto-stop via
shouldStop(result) === true - Errors notify
onErrorand keep task alive by default - Visibility behavior applies only when a document reference is injected
Key naming convention
Recommended format:
<domain>:<resource>:<id>[:variant]
Examples:
live:status:channel-123encoding:progress:vod-889jobs:chapter-sync:job-42
For complete integration patterns, see Examples.