@cadenza.io/service 2.19.1 → 2.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5497,6 +5497,8 @@ var ServiceRegistry = class _ServiceRegistry {
5497
5497
  }
5498
5498
  }
5499
5499
  }
5500
+ const hasExplicitSignalRoutingRows = signalToTaskMaps.length > 0;
5501
+ const hasExplicitIntentRoutingRows = intentToTaskMaps.length > 0;
5500
5502
  const latestManifestSnapshots = selectLatestServiceManifestSnapshots(manifestSnapshots);
5501
5503
  const explodedManifest = explodeServiceManifestSnapshots(
5502
5504
  latestManifestSnapshots
@@ -5577,26 +5579,30 @@ var ServiceRegistry = class _ServiceRegistry {
5577
5579
  row.task_version ?? 1
5578
5580
  ).trim()}`
5579
5581
  );
5580
- pushUnique(
5581
- explodedManifest.signalToTaskMaps,
5582
- signalToTaskMaps,
5583
- seenSignalMaps,
5584
- (row) => `${String(row.signal_name ?? "").trim()}|${String(
5585
- row.service_name ?? ""
5586
- ).trim()}|${String(row.task_name ?? "").trim()}|${String(
5587
- row.task_version ?? 1
5588
- ).trim()}`
5589
- );
5590
- pushUnique(
5591
- explodedManifest.intentToTaskMaps,
5592
- intentToTaskMaps,
5593
- seenIntentMaps,
5594
- (row) => `${String(row.intent_name ?? "").trim()}|${String(
5595
- row.service_name ?? ""
5596
- ).trim()}|${String(row.task_name ?? "").trim()}|${String(
5597
- row.task_version ?? 1
5598
- ).trim()}`
5599
- );
5582
+ if (!hasExplicitSignalRoutingRows) {
5583
+ pushUnique(
5584
+ explodedManifest.signalToTaskMaps,
5585
+ signalToTaskMaps,
5586
+ seenSignalMaps,
5587
+ (row) => `${String(row.signal_name ?? "").trim()}|${String(
5588
+ row.service_name ?? ""
5589
+ ).trim()}|${String(row.task_name ?? "").trim()}|${String(
5590
+ row.task_version ?? 1
5591
+ ).trim()}`
5592
+ );
5593
+ }
5594
+ if (!hasExplicitIntentRoutingRows) {
5595
+ pushUnique(
5596
+ explodedManifest.intentToTaskMaps,
5597
+ intentToTaskMaps,
5598
+ seenIntentMaps,
5599
+ (row) => `${String(row.intent_name ?? "").trim()}|${String(
5600
+ row.service_name ?? ""
5601
+ ).trim()}|${String(row.task_name ?? "").trim()}|${String(
5602
+ row.task_version ?? 1
5603
+ ).trim()}`
5604
+ );
5605
+ }
5600
5606
  return {
5601
5607
  serviceInstances,
5602
5608
  serviceInstanceTransports,
@@ -6199,16 +6205,35 @@ var ServiceRegistry = class _ServiceRegistry {
6199
6205
  const authorityFullSyncResponderTask = CadenzaService.createMetaTask(
6200
6206
  BOOTSTRAP_FULL_SYNC_RESPONDER_TASK_NAME,
6201
6207
  async (ctx) => {
6208
+ const queryOptionalAuthorityRoutingRows = async (tableName) => {
6209
+ try {
6210
+ return await DatabaseController.instance.queryAuthorityTableRows(
6211
+ tableName
6212
+ );
6213
+ } catch (error) {
6214
+ const message = error instanceof Error ? error.message : String(error);
6215
+ if (message.includes(
6216
+ `Table '${tableName}' is not registered on the CadenzaDB PostgresActor`
6217
+ )) {
6218
+ return [];
6219
+ }
6220
+ throw error;
6221
+ }
6222
+ };
6202
6223
  const [
6203
6224
  serviceInstances,
6204
6225
  serviceInstanceTransports,
6205
- serviceManifests
6226
+ serviceManifests,
6227
+ signalToTaskMaps,
6228
+ intentToTaskMaps
6206
6229
  ] = await Promise.all([
6207
6230
  DatabaseController.instance.queryAuthorityTableRows("service_instance"),
6208
6231
  DatabaseController.instance.queryAuthorityTableRows(
6209
6232
  "service_instance_transport"
6210
6233
  ),
6211
- DatabaseController.instance.queryAuthorityTableRows("service_manifest")
6234
+ DatabaseController.instance.queryAuthorityTableRows("service_manifest"),
6235
+ queryOptionalAuthorityRoutingRows("signal_to_task_map"),
6236
+ queryOptionalAuthorityRoutingRows("intent_to_task_map")
6212
6237
  ]);
6213
6238
  return {
6214
6239
  ...ctx,
@@ -6216,7 +6241,9 @@ var ServiceRegistry = class _ServiceRegistry {
6216
6241
  ...this.collectBootstrapFullSyncPayload({
6217
6242
  serviceInstances,
6218
6243
  serviceInstanceTransports,
6219
- serviceManifests
6244
+ serviceManifests,
6245
+ signalToTaskMaps,
6246
+ intentToTaskMaps
6220
6247
  })
6221
6248
  };
6222
6249
  },
@@ -12173,12 +12200,13 @@ var RuntimeValidationController = class _RuntimeValidationController {
12173
12200
  // src/graph/controllers/registerActorSessionPersistence.ts
12174
12201
  import { META_ACTOR_SESSION_STATE_PERSIST_INTENT } from "@cadenza.io/core";
12175
12202
  var ACTOR_SESSION_STATE_PERSIST_CONCURRENCY = 20;
12203
+ var META_ACTOR_SESSION_STATE_HYDRATE_INTENT = "meta-actor-session-state-hydrate";
12176
12204
  var ACTOR_SESSION_TRACE_ENABLED2 = process.env.CADENZA_ACTOR_SESSION_TRACE === "1" || process.env.CADENZA_ACTOR_SESSION_TRACE === "true";
12177
12205
  function shouldAssumeSuccessfulActorSessionRowCount(ctx) {
12178
12206
  return ctx.__success === true && ctx.rowCount === void 0 && ctx.__status === "success" && ctx.__serviceName === "CadenzaDB" && ctx.__localTaskName === "Insert actor_session_state in CadenzaDB";
12179
12207
  }
12180
12208
  function registerActorSessionPersistenceTasks() {
12181
- if (CadenzaService.get("Persist actor session state")) {
12209
+ if (CadenzaService.get("Persist actor session state") && CadenzaService.get("Hydrate actor session state")) {
12182
12210
  return;
12183
12211
  }
12184
12212
  const localActorSessionTaskOptions = {
@@ -12195,6 +12223,14 @@ function registerActorSessionPersistenceTasks() {
12195
12223
  isSubMeta: true
12196
12224
  }
12197
12225
  );
12226
+ const actorSessionStateQueryTask = CadenzaService.getLocalCadenzaDBQueryTask("actor_session_state") ?? CadenzaService.get("dbQueryActorSessionState") ?? CadenzaService.get("Query actor_session_state in CadenzaDB") ?? CadenzaService.createCadenzaDBQueryTask(
12227
+ "actor_session_state",
12228
+ {},
12229
+ {
12230
+ concurrency: ACTOR_SESSION_STATE_PERSIST_CONCURRENCY,
12231
+ isSubMeta: true
12232
+ }
12233
+ );
12198
12234
  const validateActorSessionStatePersistenceTask = CadenzaService.createMetaTask(
12199
12235
  "Validate actor session state persistence",
12200
12236
  (ctx) => {
@@ -12228,6 +12264,103 @@ function registerActorSessionPersistenceTasks() {
12228
12264
  const insertAndValidateActorSessionStateTask = actorSessionStateInsertTask.then(
12229
12265
  validateActorSessionStatePersistenceTask
12230
12266
  );
12267
+ const validateActorSessionStateHydrationTask = CadenzaService.createMetaTask(
12268
+ "Validate actor session state hydration",
12269
+ (ctx) => {
12270
+ if (ctx.errored || ctx.failed || ctx.__success !== true) {
12271
+ throw new Error(
12272
+ String(
12273
+ ctx.__error ?? ctx.error ?? "actor_session_state hydration query failed"
12274
+ )
12275
+ );
12276
+ }
12277
+ const row = ctx.actorSessionState && typeof ctx.actorSessionState === "object" && !Array.isArray(ctx.actorSessionState) ? ctx.actorSessionState : null;
12278
+ if (!row) {
12279
+ return {
12280
+ __success: true,
12281
+ hydrated: false
12282
+ };
12283
+ }
12284
+ const expiresAt = typeof row.expiresAt === "string" ? row.expiresAt : typeof row.expires_at === "string" ? row.expires_at : null;
12285
+ const expiresAtMs = expiresAt ? Date.parse(expiresAt) : Number.NaN;
12286
+ if (Number.isFinite(expiresAtMs) && expiresAtMs <= Date.now()) {
12287
+ return {
12288
+ __success: true,
12289
+ hydrated: false
12290
+ };
12291
+ }
12292
+ const durableState = row.durableState ?? row.durable_state ?? null;
12293
+ const durableVersion = Number(
12294
+ row.durableVersion ?? row.durable_version ?? Number.NaN
12295
+ );
12296
+ if (typeof durableState !== "object" || durableState === null || Array.isArray(durableState)) {
12297
+ throw new Error("actor_session_state durable_state must be a non-null object");
12298
+ }
12299
+ if (!Number.isInteger(durableVersion) || durableVersion < 0) {
12300
+ throw new Error(
12301
+ "actor_session_state durable_version must be a non-negative integer"
12302
+ );
12303
+ }
12304
+ return {
12305
+ __success: true,
12306
+ hydrated: true,
12307
+ actor_name: row.actorName ?? row.actor_name,
12308
+ actor_version: row.actorVersion ?? row.actor_version,
12309
+ actor_key: row.actorKey ?? row.actor_key,
12310
+ service_name: row.serviceName ?? row.service_name,
12311
+ durable_state: durableState,
12312
+ durable_version: durableVersion
12313
+ };
12314
+ },
12315
+ "Validates and normalizes hydrated actor_session_state rows.",
12316
+ localActorSessionTaskOptions
12317
+ );
12318
+ const queryAndValidateActorSessionStateTask = actorSessionStateQueryTask.then(
12319
+ validateActorSessionStateHydrationTask
12320
+ );
12321
+ CadenzaService.createMetaTask(
12322
+ "Hydrate actor session state",
12323
+ (ctx) => {
12324
+ const actorName = typeof ctx.actor_name === "string" ? ctx.actor_name.trim() : "";
12325
+ const actorKey = typeof ctx.actor_key === "string" ? ctx.actor_key.trim() : "";
12326
+ const actorVersion = Number(ctx.actor_version ?? 1);
12327
+ const serviceName = CadenzaService.serviceRegistry.serviceName;
12328
+ if (!actorName) {
12329
+ throw new Error("actor_name is required for actor session hydration");
12330
+ }
12331
+ if (!actorKey) {
12332
+ throw new Error("actor_key is required for actor session hydration");
12333
+ }
12334
+ if (!Number.isInteger(actorVersion) || actorVersion < 1) {
12335
+ throw new Error("actor_version must be a positive integer");
12336
+ }
12337
+ if (!serviceName) {
12338
+ throw new Error("service_name is not available for actor session hydration");
12339
+ }
12340
+ return {
12341
+ ...ctx,
12342
+ actor_name: actorName,
12343
+ actor_key: actorKey,
12344
+ actor_version: actorVersion,
12345
+ service_name: serviceName,
12346
+ queryData: {
12347
+ filter: {
12348
+ actor_name: actorName,
12349
+ actor_version: actorVersion,
12350
+ actor_key: actorKey,
12351
+ service_name: serviceName,
12352
+ deleted: false
12353
+ },
12354
+ queryMode: "one",
12355
+ sort: {
12356
+ updated: "desc"
12357
+ }
12358
+ }
12359
+ };
12360
+ },
12361
+ "Builds a one-row actor_session_state lookup for lazy actor hydration.",
12362
+ localActorSessionTaskOptions
12363
+ ).then(queryAndValidateActorSessionStateTask).respondsTo(META_ACTOR_SESSION_STATE_HYDRATE_INTENT);
12231
12364
  CadenzaService.createMetaTask(
12232
12365
  "Persist actor session state",
12233
12366
  (ctx) => {
@@ -16310,6 +16443,10 @@ function resolveInquiryFailureError(inquiry, value, depth = 3, seen = /* @__PURE
16310
16443
  }
16311
16444
  return `Inquiry '${inquiry}' did not complete successfully`;
16312
16445
  }
16446
+ function normalizePositiveInteger(value, fallback) {
16447
+ const normalized = Number(value);
16448
+ return Number.isInteger(normalized) && normalized > 0 ? normalized : fallback;
16449
+ }
16313
16450
  var DEFAULT_DEPUTY_TASK_CONCURRENCY = 50;
16314
16451
  var DEFAULT_DEPUTY_TASK_TIMEOUT_MS = 12e4;
16315
16452
  var DEFAULT_DATABASE_PROXY_TASK_CONCURRENCY = 50;
@@ -18143,11 +18280,84 @@ var CadenzaService = class {
18143
18280
  }
18144
18281
  static createActor(spec, options = {}) {
18145
18282
  this.bootstrap();
18146
- return Cadenza.createActor(spec, options);
18283
+ return Cadenza.createActor(
18284
+ spec,
18285
+ this.withActorSessionHydration(
18286
+ spec,
18287
+ options
18288
+ )
18289
+ );
18147
18290
  }
18148
18291
  static createActorFromDefinition(definition, options = {}) {
18149
18292
  this.bootstrap();
18150
- return Cadenza.createActorFromDefinition(definition, options);
18293
+ return Cadenza.createActorFromDefinition(
18294
+ definition,
18295
+ this.withActorSessionHydration(
18296
+ {
18297
+ name: definition.name,
18298
+ description: definition.description,
18299
+ defaultKey: definition.defaultKey,
18300
+ kind: definition.kind,
18301
+ loadPolicy: definition.loadPolicy,
18302
+ writeContract: definition.writeContract,
18303
+ consistencyProfile: definition.consistencyProfile,
18304
+ retry: definition.retry,
18305
+ idempotency: definition.idempotency,
18306
+ session: definition.session,
18307
+ runtimeReadGuard: definition.runtimeReadGuard,
18308
+ key: definition.key,
18309
+ state: definition.state,
18310
+ taskBindings: definition.tasks,
18311
+ initState: definition.state?.durable?.initState ?? definition.state?.durable?.initialState
18312
+ },
18313
+ options
18314
+ )
18315
+ );
18316
+ }
18317
+ static withActorSessionHydration(spec, options) {
18318
+ if (options.hydrateDurableState || spec.session?.persistDurableState !== true) {
18319
+ return options;
18320
+ }
18321
+ const actorName = String(spec.name ?? "").trim();
18322
+ const actorVersion = 1;
18323
+ const timeoutMs = normalizePositiveInteger(
18324
+ spec.session?.persistenceTimeoutMs,
18325
+ 5e3
18326
+ );
18327
+ return {
18328
+ ...options,
18329
+ hydrateDurableState: async (actorKey) => {
18330
+ registerActorSessionPersistenceTasks();
18331
+ const response = await Cadenza.inquire(
18332
+ META_ACTOR_SESSION_STATE_HYDRATE_INTENT,
18333
+ {
18334
+ actor_name: actorName,
18335
+ actor_version: actorVersion,
18336
+ actor_key: actorKey
18337
+ },
18338
+ {
18339
+ timeout: timeoutMs,
18340
+ requireComplete: true,
18341
+ rejectOnTimeout: true
18342
+ }
18343
+ );
18344
+ if (!response || typeof response !== "object" || response.__success !== true) {
18345
+ throw new Error(
18346
+ resolveInquiryFailureError(
18347
+ META_ACTOR_SESSION_STATE_HYDRATE_INTENT,
18348
+ response
18349
+ )
18350
+ );
18351
+ }
18352
+ if (response.hydrated !== true) {
18353
+ return null;
18354
+ }
18355
+ return {
18356
+ durableState: response.durable_state,
18357
+ durableVersion: Number(response.durable_version)
18358
+ };
18359
+ }
18360
+ };
18151
18361
  }
18152
18362
  /**
18153
18363
  * Creates and registers a new task with the provided name, function, and optional details.