@cadenza.io/core 3.26.0 → 3.27.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.
package/dist/index.mjs CHANGED
@@ -3853,6 +3853,7 @@ var Actor = class {
3853
3853
  this.stateByKey = /* @__PURE__ */ new Map();
3854
3854
  this.sessionByKey = /* @__PURE__ */ new Map();
3855
3855
  this.idempotencyByKey = /* @__PURE__ */ new Map();
3856
+ this.pendingHydrationByKey = /* @__PURE__ */ new Map();
3856
3857
  this.writeQueueByKey = /* @__PURE__ */ new Map();
3857
3858
  this.nextTaskBindingIndex = 0;
3858
3859
  if (!spec.name || typeof spec.name !== "string") {
@@ -3864,6 +3865,7 @@ var Actor = class {
3864
3865
  }
3865
3866
  this.kind = options.isMeta || spec.kind === "meta" ? "meta" : "standard";
3866
3867
  this.sourceDefinition = options.definitionSource;
3868
+ this.hydrateDurableState = options.hydrateDurableState;
3867
3869
  this.spec = {
3868
3870
  ...spec,
3869
3871
  defaultKey: normalizedDefaultKey,
@@ -3887,9 +3889,11 @@ var Actor = class {
3887
3889
  bindingOptions.touchSession
3888
3890
  );
3889
3891
  const actorKey = this.resolveActorKey(normalizedInput, invocationOptions);
3890
- this.touchSession(actorKey, invocationOptions.touchSession, Date.now());
3892
+ const now2 = Date.now();
3893
+ this.pruneExpiredActorKeys(now2);
3894
+ this.touchSession(actorKey, invocationOptions.touchSession, now2);
3891
3895
  const runTask = async () => {
3892
- const stateRecord = this.ensureStateRecord(actorKey);
3896
+ const stateRecord = await this.maybeHydrateStateRecord(actorKey);
3893
3897
  stateRecord.lastReadAt = Date.now();
3894
3898
  let durableStateChanged = false;
3895
3899
  let runtimeStateChanged = false;
@@ -4058,6 +4062,7 @@ var Actor = class {
4058
4062
  */
4059
4063
  getDurableState(actorKey) {
4060
4064
  const key = normalizeActorKey(actorKey) ?? this.spec.defaultKey;
4065
+ this.pruneExpiredActorKeys(Date.now());
4061
4066
  return cloneForDurableState(this.ensureStateRecord(key).durableState);
4062
4067
  }
4063
4068
  /**
@@ -4065,6 +4070,7 @@ var Actor = class {
4065
4070
  */
4066
4071
  getRuntimeState(actorKey) {
4067
4072
  const key = normalizeActorKey(actorKey) ?? this.spec.defaultKey;
4073
+ this.pruneExpiredActorKeys(Date.now());
4068
4074
  return this.ensureStateRecord(key).runtimeState;
4069
4075
  }
4070
4076
  /**
@@ -4078,6 +4084,7 @@ var Actor = class {
4078
4084
  */
4079
4085
  getDurableVersion(actorKey) {
4080
4086
  const key = normalizeActorKey(actorKey) ?? this.spec.defaultKey;
4087
+ this.pruneExpiredActorKeys(Date.now());
4081
4088
  return this.ensureStateRecord(key).version;
4082
4089
  }
4083
4090
  /**
@@ -4085,6 +4092,7 @@ var Actor = class {
4085
4092
  */
4086
4093
  getRuntimeVersion(actorKey) {
4087
4094
  const key = normalizeActorKey(actorKey) ?? this.spec.defaultKey;
4095
+ this.pruneExpiredActorKeys(Date.now());
4088
4096
  return this.ensureStateRecord(key).runtimeVersion;
4089
4097
  }
4090
4098
  /**
@@ -4127,6 +4135,7 @@ var Actor = class {
4127
4135
  this.stateByKey.clear();
4128
4136
  this.sessionByKey.clear();
4129
4137
  this.idempotencyByKey.clear();
4138
+ this.pendingHydrationByKey.clear();
4130
4139
  if ((this.spec.loadPolicy ?? "eager") === "eager") {
4131
4140
  this.ensureStateRecord(this.spec.defaultKey);
4132
4141
  }
@@ -4138,6 +4147,7 @@ var Actor = class {
4138
4147
  }
4139
4148
  this.stateByKey.delete(normalizedKey);
4140
4149
  this.sessionByKey.delete(normalizedKey);
4150
+ this.pendingHydrationByKey.delete(normalizedKey);
4141
4151
  for (const key of this.idempotencyByKey.keys()) {
4142
4152
  if (key.startsWith(`${normalizedKey}:`)) {
4143
4153
  this.idempotencyByKey.delete(key);
@@ -4223,6 +4233,7 @@ var Actor = class {
4223
4233
  runtimeState: this.resolveInitialRuntimeState(),
4224
4234
  version: 0,
4225
4235
  runtimeVersion: 0,
4236
+ hydrationResolved: this.hydrateDurableState === void 0,
4226
4237
  createdAt: now2,
4227
4238
  lastReadAt: now2,
4228
4239
  lastDurableWriteAt: now2,
@@ -4232,6 +4243,54 @@ var Actor = class {
4232
4243
  this.touchSession(actorKey, true, now2);
4233
4244
  return record;
4234
4245
  }
4246
+ async maybeHydrateStateRecord(actorKey) {
4247
+ const record = this.ensureStateRecord(actorKey);
4248
+ if (record.hydrationResolved || !this.hydrateDurableState) {
4249
+ return record;
4250
+ }
4251
+ const pending = this.pendingHydrationByKey.get(actorKey);
4252
+ if (pending) {
4253
+ return pending;
4254
+ }
4255
+ let hydrationPromise;
4256
+ hydrationPromise = (async () => {
4257
+ const current = this.ensureStateRecord(actorKey);
4258
+ if (current.hydrationResolved || !this.hydrateDurableState) {
4259
+ return current;
4260
+ }
4261
+ const snapshot = await this.hydrateDurableState(actorKey);
4262
+ const latest = this.ensureStateRecord(actorKey);
4263
+ if (latest.hydrationResolved) {
4264
+ return latest;
4265
+ }
4266
+ if (snapshot) {
4267
+ const durableVersion = Number(snapshot.durableVersion);
4268
+ if (!Number.isInteger(durableVersion) || durableVersion < 0) {
4269
+ throw new Error(
4270
+ `Actor "${this.spec.name}" received invalid hydrated durable version for key "${actorKey}"`
4271
+ );
4272
+ }
4273
+ if (!isObject2(snapshot.durableState) || Array.isArray(snapshot.durableState)) {
4274
+ throw new Error(
4275
+ `Actor "${this.spec.name}" received invalid hydrated durable state for key "${actorKey}"`
4276
+ );
4277
+ }
4278
+ const hydratedAt = Date.now();
4279
+ latest.durableState = cloneForDurableState(snapshot.durableState);
4280
+ latest.version = durableVersion;
4281
+ latest.lastReadAt = hydratedAt;
4282
+ latest.lastDurableWriteAt = hydratedAt;
4283
+ }
4284
+ latest.hydrationResolved = true;
4285
+ return latest;
4286
+ })().finally(() => {
4287
+ if (this.pendingHydrationByKey.get(actorKey) === hydrationPromise) {
4288
+ this.pendingHydrationByKey.delete(actorKey);
4289
+ }
4290
+ });
4291
+ this.pendingHydrationByKey.set(actorKey, hydrationPromise);
4292
+ return hydrationPromise;
4293
+ }
4235
4294
  touchSession(actorKey, shouldTouch, touchedAt) {
4236
4295
  if (!this.spec.session?.enabled || !shouldTouch) {
4237
4296
  return;
@@ -4255,6 +4314,30 @@ var Actor = class {
4255
4314
  existing.absoluteExpiresAt = touchedAt + absoluteTtlMs;
4256
4315
  }
4257
4316
  }
4317
+ pruneExpiredActorKeys(now2) {
4318
+ if (!this.spec.session?.enabled || this.sessionByKey.size === 0) {
4319
+ return;
4320
+ }
4321
+ for (const [actorKey, session] of this.sessionByKey.entries()) {
4322
+ if (!this.isSessionExpired(session, now2)) {
4323
+ continue;
4324
+ }
4325
+ if (this.writeQueueByKey.has(actorKey)) {
4326
+ continue;
4327
+ }
4328
+ this.stateByKey.delete(actorKey);
4329
+ this.sessionByKey.delete(actorKey);
4330
+ }
4331
+ }
4332
+ isSessionExpired(session, now2) {
4333
+ if (session.absoluteExpiresAt !== null && now2 >= session.absoluteExpiresAt) {
4334
+ return true;
4335
+ }
4336
+ if (session.idleExpiresAt !== null && now2 >= session.idleExpiresAt) {
4337
+ return true;
4338
+ }
4339
+ return false;
4340
+ }
4258
4341
  runWithOptionalIdempotency(taskBindingId, actorKey, options, runTask) {
4259
4342
  const idempotencyPolicy = this.spec.idempotency;
4260
4343
  const enabled = idempotencyPolicy?.enabled ?? false;
@@ -7305,7 +7388,8 @@ var Cadenza = class {
7305
7388
  };
7306
7389
  const actorOptions = {
7307
7390
  isMeta: options.isMeta,
7308
- definitionSource: definition
7391
+ definitionSource: definition,
7392
+ hydrateDurableState: options.hydrateDurableState
7309
7393
  };
7310
7394
  return this.createActor(spec, actorOptions);
7311
7395
  }