Extract cache query runtime

master
dev 5 months ago
parent c0753b523d
commit 000178fdc4

@ -35,6 +35,7 @@ Estado al cierre:
- `arts/sium/core/pipe.ts` queda centrado en composicion; factories `refine/transform/codec/meta` viven en `steps.ts`.
- `libs/cach/engine.ts` delega lectura `get()` en `runtime-get.ts`.
- `libs/cach/engine.ts` delega escritura `set()` en `runtime-set.ts`.
- `libs/cach/engine.ts` delega `query()` en `runtime-query.ts`; conserva composition root para context/io/delete/invalidate/mutate/explain.
- `arts/conn/connection.ts` delega decode/routing de frames entrantes en `connection-message-router.ts`.
- `arts/conn/connection.ts` delega el intento open/auth/flush/join en `connection-connect.ts`.
- `arts/conn/connection.ts` delega current transport, attach/detach y close en `connection-transport-runtime.ts`.

@ -1,43 +1,23 @@
import {
CACHE_CONTEXT_REASON_FETCH_ERROR,
CACHE_CONTEXT_REASON_GET,
CACHE_CONTEXT_REASON_JOINED_EXISTING_FETCH,
CACHE_DECISION_ACTION_DELETE_AND_FETCH,
CACHE_DECISION_ACTION_SERVE,
CACHE_DECISION_ACTION_SERVE_AND_REFRESH,
CACHE_DECISION_REASON_BYPASS_CACHE,
CACHE_DECISION_REASON_CACHE_MISS,
CACHE_DECISION_REASON_NO_STORE,
CACHE_DEFAULT_NAMESPACE,
CACHE_DEFAULT_VERSION,
CACHE_EVENT_ADAPTER_ERROR,
CACHE_EVENT_HIT,
CACHE_EVENT_MISS,
CACHE_EVENT_SCHEMA_MISMATCH,
CACHE_EVENT_SINGLEFLIGHT_JOIN,
CACHE_EVENT_STALE_HIT,
CACHE_EVENT_STALE_IF_ERROR,
CACHE_READ_MODE_BYPASS_CACHE,
CACHE_READ_MODE_NO_STORE,
CACHE_READ_MODE_STALE_WHILE_REVALIDATE
CACHE_EVENT_SINGLEFLIGHT_JOIN
} from './consts.ts';
import { CacheEvents } from './events.ts';
import { normalizeTags } from './key.ts';
import {
resolveCacheContext,
type CacheContextInput,
type ResolvedCacheContext
} from './runtime-context.ts';
import { createCacheRuntimeDelete } from './runtime-delete.ts';
import {
canServeCacheStaleIfError,
evaluateCacheEntry
} from './runtime-evaluation.ts';
import { evaluateCacheEntry } from './runtime-evaluation.ts';
import { readCacheCurrentEpochs } from './runtime-epochs.ts';
import { buildCacheHitExplain, buildCacheMissExplain } from './runtime-explain.ts';
import { createCacheRuntimeGet } from './runtime-get.ts';
import { invalidateCacheEntry } from './runtime-invalidation.ts';
import { createCacheRuntimeIo } from './runtime-io.ts';
import { createCacheRuntimeQuery } from './runtime-query.ts';
import { createCacheRuntimeSet } from './runtime-set.ts';
import { systemCacheClock } from './runtime-helpers.ts';
import { runCacheMutation } from './runtime-mutation.ts';
@ -135,78 +115,18 @@ export function createCacheRuntime(config: CacheRuntimeConfig): CacheRuntime {
});
}
async function query<T>(options: QueryOptions<T>): Promise<T> {
const ctx = await contextFor(options);
if (
ctx.policy.mode === CACHE_READ_MODE_BYPASS_CACHE ||
ctx.policy.mode === CACHE_READ_MODE_NO_STORE
) {
const reason =
ctx.policy.mode === CACHE_READ_MODE_BYPASS_CACHE
? CACHE_DECISION_REASON_BYPASS_CACHE
: CACHE_DECISION_REASON_NO_STORE;
emitForContext(CACHE_EVENT_MISS, ctx, { reason });
const value = await options.fetcher();
if (ctx.policy.mode === CACHE_READ_MODE_BYPASS_CACHE) {
const envelope = await io.createEnvelope(value, ctx, normalizeTags(options.tags));
await io.writeEnvelope(ctx, envelope);
}
return value;
}
let cached: CacheEnvelope<T> | null = null;
try {
cached = await adapter.get<T>(ctx.fullKey);
} catch (error) {
emit(CACHE_EVENT_ADAPTER_ERROR, {
key: ctx.fullKey,
keyHash: ctx.keyHash,
error,
reason: CACHE_CONTEXT_REASON_GET
});
throw error;
}
if (cached) {
const decision = await evaluate(cached, ctx);
if (decision.action === CACHE_DECISION_ACTION_SERVE) {
emitForContext(CACHE_EVENT_HIT, ctx, { reason: decision.reason });
return cached.value;
}
if (decision.action === CACHE_DECISION_ACTION_SERVE_AND_REFRESH) {
emitForContext(CACHE_EVENT_STALE_HIT, ctx, { reason: decision.reason });
await backgroundRefresh(ctx, options);
return cached.value;
}
if (decision.action === CACHE_DECISION_ACTION_DELETE_AND_FETCH) {
emitForContext(CACHE_EVENT_SCHEMA_MISMATCH, ctx, { reason: decision.reason });
await deletion.safeDelete(ctx.fullKey, ctx.keyHash);
}
} else {
emitForContext(CACHE_EVENT_MISS, ctx, { reason: CACHE_DECISION_REASON_CACHE_MISS });
}
return singleflight.run(ctx.fullKey, async () => {
try {
return await io.fetchAndStore(ctx, options);
} catch (error) {
if (cached && canServeCacheStaleIfError(cached, clock.now())) {
emitForContext(CACHE_EVENT_STALE_IF_ERROR, ctx, {
reason: CACHE_CONTEXT_REASON_FETCH_ERROR,
error
});
return cached.value;
}
throw error;
}
const query = createCacheRuntimeQuery({
adapter,
deletion,
io,
singleflight,
now: () => clock.now(),
contextFor,
evaluate,
backgroundRefresh,
emit,
emitForContext
});
}
const get = createCacheRuntimeGet({ adapter, deletion, contextFor, evaluate, emitForContext });
const set = createCacheRuntimeSet({ io, contextFor });

@ -0,0 +1,123 @@
import {
CACHE_CONTEXT_REASON_FETCH_ERROR,
CACHE_CONTEXT_REASON_GET,
CACHE_DECISION_ACTION_DELETE_AND_FETCH,
CACHE_DECISION_ACTION_SERVE,
CACHE_DECISION_ACTION_SERVE_AND_REFRESH,
CACHE_DECISION_REASON_BYPASS_CACHE,
CACHE_DECISION_REASON_CACHE_MISS,
CACHE_DECISION_REASON_NO_STORE,
CACHE_EVENT_ADAPTER_ERROR,
CACHE_EVENT_HIT,
CACHE_EVENT_MISS,
CACHE_EVENT_SCHEMA_MISMATCH,
CACHE_EVENT_STALE_HIT,
CACHE_EVENT_STALE_IF_ERROR,
CACHE_READ_MODE_BYPASS_CACHE,
CACHE_READ_MODE_NO_STORE
} from './consts.ts';
import { normalizeTags } from './key.ts';
import type { CacheContextInput, ResolvedCacheContext } from './runtime-context.ts';
import type { CacheRuntimeDelete } from './runtime-delete.ts';
import { canServeCacheStaleIfError } from './runtime-evaluation.ts';
import type { CacheRuntimeIo } from './runtime-io.ts';
import type { Singleflight } from './singleflight.ts';
import type {
CacheAdapter,
CacheDecision,
CacheEnvelope,
CacheEvent,
CacheEventType,
QueryOptions
} from './types.ts';
interface CacheRuntimeQueryInput {
readonly adapter: CacheAdapter;
readonly deletion: CacheRuntimeDelete;
readonly io: CacheRuntimeIo;
readonly singleflight: Singleflight;
now(): number;
contextFor(input: CacheContextInput): Promise<ResolvedCacheContext>;
evaluate<T>(entry: CacheEnvelope<T>, ctx: ResolvedCacheContext): Promise<CacheDecision>;
backgroundRefresh<T>(ctx: ResolvedCacheContext, options: QueryOptions<T>): Promise<void>;
emit(type: CacheEventType, patch?: Partial<CacheEvent>): void;
emitForContext(
type: CacheEventType,
ctx: ResolvedCacheContext,
patch?: Partial<CacheEvent>
): void;
}
export function createCacheRuntimeQuery(runtime: CacheRuntimeQueryInput) {
return async function query<T>(options: QueryOptions<T>): Promise<T> {
const ctx = await runtime.contextFor(options);
if (
ctx.policy.mode === CACHE_READ_MODE_BYPASS_CACHE ||
ctx.policy.mode === CACHE_READ_MODE_NO_STORE
) {
const reason =
ctx.policy.mode === CACHE_READ_MODE_BYPASS_CACHE
? CACHE_DECISION_REASON_BYPASS_CACHE
: CACHE_DECISION_REASON_NO_STORE;
runtime.emitForContext(CACHE_EVENT_MISS, ctx, { reason });
const value = await options.fetcher();
if (ctx.policy.mode === CACHE_READ_MODE_BYPASS_CACHE) {
const envelope = await runtime.io.createEnvelope(value, ctx, normalizeTags(options.tags));
await runtime.io.writeEnvelope(ctx, envelope);
}
return value;
}
let cached: CacheEnvelope<T> | null = null;
try {
cached = await runtime.adapter.get<T>(ctx.fullKey);
} catch (error) {
runtime.emit(CACHE_EVENT_ADAPTER_ERROR, {
key: ctx.fullKey,
keyHash: ctx.keyHash,
error,
reason: CACHE_CONTEXT_REASON_GET
});
throw error;
}
if (cached) {
const decision = await runtime.evaluate(cached, ctx);
if (decision.action === CACHE_DECISION_ACTION_SERVE) {
runtime.emitForContext(CACHE_EVENT_HIT, ctx, { reason: decision.reason });
return cached.value;
}
if (decision.action === CACHE_DECISION_ACTION_SERVE_AND_REFRESH) {
runtime.emitForContext(CACHE_EVENT_STALE_HIT, ctx, { reason: decision.reason });
await runtime.backgroundRefresh(ctx, options);
return cached.value;
}
if (decision.action === CACHE_DECISION_ACTION_DELETE_AND_FETCH) {
runtime.emitForContext(CACHE_EVENT_SCHEMA_MISMATCH, ctx, { reason: decision.reason });
await runtime.deletion.safeDelete(ctx.fullKey, ctx.keyHash);
}
} else {
runtime.emitForContext(CACHE_EVENT_MISS, ctx, { reason: CACHE_DECISION_REASON_CACHE_MISS });
}
return runtime.singleflight.run(ctx.fullKey, async () => {
try {
return await runtime.io.fetchAndStore(ctx, options);
} catch (error) {
if (cached && canServeCacheStaleIfError(cached, runtime.now())) {
runtime.emitForContext(CACHE_EVENT_STALE_IF_ERROR, ctx, {
reason: CACHE_CONTEXT_REASON_FETCH_ERROR,
error
});
return cached.value;
}
throw error;
}
});
};
}
Loading…
Cancel
Save

Powered by TurnKey Linux.