Move timer entry runtime helpers

master
dev 5 months ago
parent c848da24c4
commit cdce5de04e

@ -27,6 +27,7 @@ Estado al cierre:
- `arts/timr/engine-timers.ts` delega fan-out de listeners y diagnostico de listeners en `timer-events.ts`.
- `arts/timr/engine-timers.ts` delega la construccion de entradas internas en `timer-entry.ts`.
- `arts/timr/engine-timers.ts` delega cancelacion y seleccion por scope en `timer-cancel.ts`.
- `arts/timr/engine-timers.ts` delega entrada viva, contexto de task y max-runs en `timer-entry.ts`.
- Integracion total ampliada: `Auth.signOut()` valida anonimizacion, invalidacion de `Permissions` y evento `Cache.invalidate`.
- Tanda focalizada verde: `npx vitest run src/arts/conn src/libs/cach src/arts/cach src/svrs/cach src/arts/auth src/svrs/auth src/libs/auth src/arts/aapp/test/ecosystem.integration.test.ts` -> 19 archivos, 82 tests.
- `/test/ecosystem` revisado en navegador: carga sin errores de consola, `ar` cambia a `rtl`, Formats se actualiza por locale, Perm cambia con rol `viewer`, Cach re-scopea por locale y Conn loopback publica/recibe.

@ -48,6 +48,9 @@ import { TimrDuplicateKeyError } from './errors.ts';
import { cancelTimerEntry, collectTimerKeysInScope } from './timer-cancel.ts';
import {
createInternalTimerEntry,
createTimerTaskContext,
getLiveTimerEntry,
hasTimerReachedMaxRuns,
timerEntrySnapshot,
type InternalTimerEntry
} from './timer-entry.ts';
@ -68,8 +71,7 @@ import type {
TimerIntervalOptions,
TimerKind,
TimerOptions,
TimerTask,
TimerTaskContext
TimerTask
} from './types.ts';
export function createEngineTimers(options: EngineTimersOptions = {}): EngineTimers {
@ -94,19 +96,6 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim
// ── Entry lifecycle ─────────────────────────────────────────────────────
/**
* Look up an entry only if the captured tuple still matches. This is
* the core of the race-safety contract — every callback uses it.
*/
function getLiveEntry(id: number, key: string, version: number): InternalTimerEntry | null {
const current = entries.get(key);
if (current === undefined) return null;
if (current.id !== id) return null;
if (current.version !== version) return null;
if (current.controller.signal.aborted) return null;
return current;
}
/**
* Arm the native timeout for the given entry. Captures the tuple in
* the closure — `runEntry` will reject the callback if the entry has
@ -122,21 +111,8 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim
}, delayMs);
}
function makeContext(entry: InternalTimerEntry, firedAt: number): TimerTaskContext {
return {
key: entry.key,
kind: entry.kind,
scheduledAt: entry.scheduledAt,
dueAt: entry.dueAt,
firedAt,
driftMs: firedAt - entry.dueAt,
runCount: entry.runCount,
signal: entry.controller.signal
};
}
async function runEntry(id: number, key: string, version: number): Promise<void> {
const entry = getLiveEntry(id, key, version);
const entry = getLiveTimerEntry(entries, id, key, version);
if (entry === null) return;
if (entry.status !== TIMER_STATUS_PENDING) return;
@ -145,7 +121,7 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim
entry.lastFiredAt = firedAt;
entry.runCount += 1;
entry.native = null;
const ctx = makeContext(entry, firedAt);
const ctx = createTimerTaskContext(entry, firedAt);
emit({ type: TIMER_EVENT_RUNNING, entry: timerEntrySnapshot(entry) });
const isInterval = entry.kind === TIMER_KIND_INTERVAL;
@ -154,7 +130,7 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim
// Branch A — interval with awaitTask=false: arm the next tick BEFORE
// running so we honour cadence regardless of how long the task
// takes. Stale-callback guard still applies to next tick.
if (isInterval && !awaitTask && !hasReachedMaxRuns(entry)) {
if (isInterval && !awaitTask && !hasTimerReachedMaxRuns(entry)) {
scheduleNextIntervalTick(entry);
}
@ -204,7 +180,7 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim
// `entry.status` may already be TIMER_STATUS_PENDING if branch A
// already armed the next tick; otherwise schedule it now.
if (entry.status === TIMER_STATUS_RUNNING) {
if (hasReachedMaxRuns(entry)) {
if (hasTimerReachedMaxRuns(entry)) {
entry.status = error === null ? TIMER_STATUS_COMPLETED : TIMER_STATUS_FAILED;
entries.delete(entry.key);
return;
@ -221,7 +197,7 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim
function scheduleNextIntervalTick(entry: InternalTimerEntry): void {
if (entry.intervalMs === null) return;
if (hasReachedMaxRuns(entry)) {
if (hasTimerReachedMaxRuns(entry)) {
entry.status = TIMER_STATUS_COMPLETED;
entries.delete(entry.key);
return;
@ -242,10 +218,6 @@ export function createEngineTimers(options: EngineTimersOptions = {}): EngineTim
// ── Public scheduling ───────────────────────────────────────────────────
function hasReachedMaxRuns(entry: InternalTimerEntry): boolean {
return entry.maxRuns !== undefined && entry.runCount >= entry.maxRuns;
}
function scheduleCommon(
key: string,
delayMs: number,

@ -4,7 +4,8 @@ import type {
TimerKind,
TimerNativeHandle,
TimerStatus,
TimerTask
TimerTask,
TimerTaskContext
} from './types.ts';
export interface InternalTimerEntry {
@ -71,6 +72,40 @@ export function createInternalTimerEntry(input: CreateInternalTimerEntryInput):
};
}
export function getLiveTimerEntry(
entries: Map<string, InternalTimerEntry>,
id: number,
key: string,
version: number
): InternalTimerEntry | null {
const current = entries.get(key);
if (current === undefined) return null;
if (current.id !== id) return null;
if (current.version !== version) return null;
if (current.controller.signal.aborted) return null;
return current;
}
export function createTimerTaskContext(
entry: InternalTimerEntry,
firedAt: number
): TimerTaskContext {
return {
key: entry.key,
kind: entry.kind,
scheduledAt: entry.scheduledAt,
dueAt: entry.dueAt,
firedAt,
driftMs: firedAt - entry.dueAt,
runCount: entry.runCount,
signal: entry.controller.signal
};
}
export function hasTimerReachedMaxRuns(entry: InternalTimerEntry): boolean {
return entry.maxRuns !== undefined && entry.runCount >= entry.maxRuns;
}
export function scopeOfTimerKey(key: string): string {
const idx = key.lastIndexOf(DEFAULT_TIMER_SCOPE_SEPARATOR);
return idx === -1 ? key : key.slice(0, idx);

Loading…
Cancel
Save

Powered by TurnKey Linux.