experimental-a2 0.18.0 → 0.18.1
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/CHANGELOG.md +11 -0
- package/dist/{actor-Bjce9_5U.d.ts → actor-C7b-1arn.d.ts} +3 -3
- package/dist/{actor-Bjce9_5U.d.ts.map → actor-C7b-1arn.d.ts.map} +1 -1
- package/dist/actor-client.d.ts +1 -1
- package/dist/actor-react.d.ts +1 -1
- package/dist/actor-react.js +1 -1
- package/dist/actor.d.ts +1 -1
- package/dist/actor.js +2 -2
- package/dist/{ai-DrUaMyRt.d.ts → ai-BMLlI2Ff.d.ts} +2 -2
- package/dist/{ai-DrUaMyRt.d.ts.map → ai-BMLlI2Ff.d.ts.map} +1 -1
- package/dist/{ai-BpOGm-zB.js → ai-D6mGlO8j.js} +2 -2
- package/dist/{ai-BpOGm-zB.js.map → ai-D6mGlO8j.js.map} +1 -1
- package/dist/ai-client.d.ts +1 -1
- package/dist/ai-client.js +2 -2
- package/dist/ai-fx.d.ts +1 -1
- package/dist/ai-fx.d.ts.map +1 -1
- package/dist/ai-fx.js +92 -34
- package/dist/ai-fx.js.map +1 -1
- package/dist/{ai-harness-DvsPeJeB.d.ts → ai-harness-B2suP2Qh.d.ts} +2 -2
- package/dist/{ai-harness-DvsPeJeB.d.ts.map → ai-harness-B2suP2Qh.d.ts.map} +1 -1
- package/dist/ai-pi.d.ts +1 -1
- package/dist/ai-pi.d.ts.map +1 -1
- package/dist/ai-pi.js +59 -13
- package/dist/ai-pi.js.map +1 -1
- package/dist/ai-react.d.ts +1 -1
- package/dist/ai-react.js +2 -2
- package/dist/ai-server.d.ts +3 -3
- package/dist/ai-server.d.ts.map +1 -1
- package/dist/ai-server.js +10 -6
- package/dist/ai-server.js.map +1 -1
- package/dist/ai-tool-input-DmSqMUQi.js +40 -0
- package/dist/ai-tool-input-DmSqMUQi.js.map +1 -0
- package/dist/ai.d.ts +1 -1
- package/dist/ai.js +1 -1
- package/dist/{client-BReKqwZC.js → client-BhHLoNKF.js} +3 -3
- package/dist/{client-BReKqwZC.js.map → client-BhHLoNKF.js.map} +1 -1
- package/dist/client.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/{internal-B2T3U4Rq.js → internal-CscSY7K_.js} +4 -2
- package/dist/{internal-B2T3U4Rq.js.map → internal-CscSY7K_.js.map} +1 -1
- package/dist/react.js +1 -1
- package/dist/scheduler-qstash.d.ts +2 -2
- package/dist/scheduler-qstash.js +3 -3
- package/dist/scheduler-qstash.js.map +1 -1
- package/dist/scheduler-vercel.d.ts +7 -7
- package/dist/scheduler-vercel.d.ts.map +1 -1
- package/dist/scheduler-vercel.js +9 -10
- package/dist/scheduler-vercel.js.map +1 -1
- package/dist/{server-Dw_k_7kO.js → server-D-Y4pqwu.js} +37 -11
- package/dist/server-D-Y4pqwu.js.map +1 -0
- package/dist/{server-En7cbi3v.d.ts → server-DYAATFuT.d.ts} +11 -5
- package/dist/server-DYAATFuT.d.ts.map +1 -0
- package/dist/server.d.ts +2 -2
- package/dist/server.js +1 -1
- package/dist/{session-clear-Bo-XTFEy.d.ts → session-clear-C-QwTXV1.d.ts} +2 -2
- package/dist/session-clear-C-QwTXV1.d.ts.map +1 -0
- package/dist/{store-Djdv0bnZ.d.ts → store-CyLUy86v.d.ts} +23 -4
- package/dist/store-CyLUy86v.d.ts.map +1 -0
- package/dist/store-N8PXxDAS.js.map +1 -1
- package/dist/store-memory.d.ts +1 -1
- package/dist/store-memory.js +25 -6
- package/dist/store-memory.js.map +1 -1
- package/dist/{store-polling-B5FcwJfo.js → store-polling-7WJV0YWP.js} +2 -2
- package/dist/{store-polling-B5FcwJfo.js.map → store-polling-7WJV0YWP.js.map} +1 -1
- package/dist/store-postgres.d.ts +1 -1
- package/dist/store-postgres.d.ts.map +1 -1
- package/dist/store-postgres.js +55 -25
- package/dist/store-postgres.js.map +1 -1
- package/dist/{store-presence-polling-BAwS8RWn.js → store-presence-polling-B1ixeqIS.js} +3 -3
- package/dist/{store-presence-polling-BAwS8RWn.js.map → store-presence-polling-B1ixeqIS.js.map} +1 -1
- package/dist/store-redis-http.d.ts +1 -1
- package/dist/store-redis-http.js +3 -3
- package/dist/{store-redis-notify-BRITti_o.js → store-redis-notify-CM0AfLY0.js} +88 -37
- package/dist/store-redis-notify-CM0AfLY0.js.map +1 -0
- package/dist/store-redis.d.ts +1 -1
- package/dist/store-redis.js +1 -1
- package/dist/store-sqlite.d.ts +1 -1
- package/dist/store-sqlite.js +35 -20
- package/dist/store-sqlite.js.map +1 -1
- package/dist/{wire-rSUglYo8.js → wire-BKxH1vbP.js} +2 -2
- package/dist/{wire-rSUglYo8.js.map → wire-BKxH1vbP.js.map} +1 -1
- package/docs/agents/03-conversations.mdx +2 -2
- package/docs/index.mdx +3 -3
- package/docs/reference/02-server.mdx +12 -7
- package/docs/reference/04-ai.mdx +16 -7
- package/docs/reference/05-adapters.mdx +4 -4
- package/docs/server/01-handlers.mdx +1 -1
- package/docs/server/03-cancellation.mdx +3 -2
- package/docs/server/05-production.mdx +2 -1
- package/docs/server/06-guarantees.mdx +20 -11
- package/examples/playground/DEPLOY.md +2 -4
- package/examples/playground/app/a0/[appId]/page.tsx +2 -8
- package/examples/playground/app/a0/devtools.tsx +2 -8
- package/examples/playground/app/a0/server.ts +8 -19
- package/examples/playground/package.json +1 -1
- package/package.json +1 -1
- package/src/ai-agent.ts +10 -3
- package/src/ai-fx.ts +126 -47
- package/src/ai-pi.ts +74 -15
- package/src/ai-tool-input.ts +45 -0
- package/src/internal.ts +6 -0
- package/src/scheduler-qstash.ts +5 -5
- package/src/scheduler-vercel.ts +14 -15
- package/src/server.ts +58 -12
- package/src/store-memory.ts +50 -9
- package/src/store-postgres.ts +79 -28
- package/src/store-redis-core.ts +112 -31
- package/src/store-sqlite.ts +61 -28
- package/src/store.ts +22 -3
- package/dist/server-Dw_k_7kO.js.map +0 -1
- package/dist/server-En7cbi3v.d.ts.map +0 -1
- package/dist/session-clear-Bo-XTFEy.d.ts.map +0 -1
- package/dist/store-Djdv0bnZ.d.ts.map +0 -1
- package/dist/store-redis-notify-BRITti_o.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { i as POLL_TIMINGS } from "./internal-
|
|
2
|
-
import { t as defaultSleep } from "./store-polling-
|
|
1
|
+
import { i as POLL_TIMINGS } from "./internal-CscSY7K_.js";
|
|
2
|
+
import { t as defaultSleep } from "./store-polling-7WJV0YWP.js";
|
|
3
3
|
//#region src/store-presence-polling.ts
|
|
4
4
|
const key = ({ participant, field }) => JSON.stringify([participant, field]);
|
|
5
5
|
function pollPresence({ read, deliver, sleep = defaultSleep }) {
|
|
@@ -91,4 +91,4 @@ function pollPresence({ read, deliver, sleep = defaultSleep }) {
|
|
|
91
91
|
//#endregion
|
|
92
92
|
export { pollPresence as t };
|
|
93
93
|
|
|
94
|
-
//# sourceMappingURL=store-presence-polling-
|
|
94
|
+
//# sourceMappingURL=store-presence-polling-B1ixeqIS.js.map
|
package/dist/{store-presence-polling-BAwS8RWn.js.map → store-presence-polling-B1ixeqIS.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store-presence-polling-
|
|
1
|
+
{"version":3,"file":"store-presence-polling-B1ixeqIS.js","names":[],"sources":["../src/store-presence-polling.ts"],"sourcesContent":["import type { PresencePatch } from './contract.ts'\nimport { POLL_TIMINGS } from './internal.ts'\nimport { defaultSleep, type Sleeper } from './store-polling.ts'\nimport type { PresenceRow } from './store.ts'\n\nconst key = ({\n participant,\n field,\n}: Pick<PresenceRow, 'participant' | 'field'>): string =>\n JSON.stringify([participant, field])\n\nexport function pollPresence({\n read,\n deliver,\n sleep = defaultSleep,\n}: {\n read: () => Promise<PresenceRow[]>\n deliver: (patch: PresencePatch) => void\n sleep?: (ms: number) => Sleeper\n}): {\n ready: Promise<void>\n update(patch: PresencePatch): void\n wake(): void\n stop(): void\n} {\n let stopped = false\n let pending: Sleeper | undefined\n let interval = Math.min(\n POLL_TIMINGS.activeFloorMs,\n POLL_TIMINGS.idleCeilingMs,\n )\n let version = 0\n const seen = new Map<string, Omit<PresenceRow, 'expiresAt'>>()\n const activate = (): void => {\n version += 1\n interval = Math.min(POLL_TIMINGS.activeFloorMs, POLL_TIMINGS.idleCeilingMs)\n pending?.cancel()\n }\n const ready = read()\n .then((rows) => {\n if (stopped) return\n for (const row of rows) seen.set(key(row), row)\n return undefined\n })\n // Seeding is best effort; foreground snapshots still report read errors.\n .catch(() => undefined)\n\n const run = async (): Promise<void> => {\n await ready\n for (;;) {\n if (stopped) return\n const before = version\n pending = sleep(interval)\n // oxlint-disable-next-line no-await-in-loop -- adaptive presence polling\n await pending.promise\n if (stopped) return\n try {\n const reading = version\n // oxlint-disable-next-line no-await-in-loop -- read each new presence snapshot\n const rows = await read()\n if (stopped) return\n if (version !== reading) continue\n const live = new Set<string>()\n let changed = false\n for (const row of rows) {\n const id = key(row)\n live.add(id)\n const prior = seen.get(id)\n seen.set(id, row)\n if (\n prior?.seen === row.seen &&\n prior.at.getTime() === row.at.getTime() &&\n JSON.stringify(prior.value) === JSON.stringify(row.value)\n )\n continue\n changed = true\n deliver({\n participant: row.participant,\n values: { [row.field]: row.value },\n seen: row.seen,\n at: row.at,\n })\n }\n for (const [id, row] of seen) {\n if (live.has(id)) continue\n seen.delete(id)\n changed = true\n deliver({\n participant: row.participant,\n values: { [row.field]: null },\n seen: row.seen,\n at: new Date(),\n })\n }\n if (changed) activate()\n else if (version === before)\n interval = Math.min(interval * 2, POLL_TIMINGS.idleCeilingMs)\n } catch {\n interval = POLL_TIMINGS.idleCeilingMs\n }\n }\n }\n void run()\n return {\n ready,\n wake: activate,\n update(patch) {\n for (const [field, value] of Object.entries(patch.values)) {\n seen.set(key({ participant: patch.participant, field }), {\n participant: patch.participant,\n field,\n value,\n seen: patch.seen,\n at: patch.at,\n })\n }\n activate()\n },\n stop() {\n stopped = true\n pending?.cancel()\n seen.clear()\n },\n }\n}\n"],"mappings":";;;AAKA,MAAM,OAAO,EACX,aACA,YAEA,KAAK,UAAU,CAAC,aAAa,KAAK,CAAC;AAErC,SAAgB,aAAa,EAC3B,MACA,SACA,QAAQ,gBAUR;CACA,IAAI,UAAU;CACd,IAAI;CACJ,IAAI,WAAW,KAAK,IAClB,aAAa,eACb,aAAa,aACf;CACA,IAAI,UAAU;CACd,MAAM,uBAAO,IAAI,IAA4C;CAC7D,MAAM,iBAAuB;EAC3B,WAAW;EACX,WAAW,KAAK,IAAI,aAAa,eAAe,aAAa,aAAa;EAC1E,SAAS,OAAO;CAClB;CACA,MAAM,QAAQ,KAAK,CAAC,CACjB,MAAM,SAAS;EACd,IAAI,SAAS;EACb,KAAK,MAAM,OAAO,MAAM,KAAK,IAAI,IAAI,GAAG,GAAG,GAAG;CAEhD,CAAC,CAAC,CAED,YAAY,KAAA,CAAS;CAExB,MAAM,MAAM,YAA2B;EACrC,MAAM;EACN,SAAS;GACP,IAAI,SAAS;GACb,MAAM,SAAS;GACf,UAAU,MAAM,QAAQ;GAExB,MAAM,QAAQ;GACd,IAAI,SAAS;GACb,IAAI;IACF,MAAM,UAAU;IAEhB,MAAM,OAAO,MAAM,KAAK;IACxB,IAAI,SAAS;IACb,IAAI,YAAY,SAAS;IACzB,MAAM,uBAAO,IAAI,IAAY;IAC7B,IAAI,UAAU;IACd,KAAK,MAAM,OAAO,MAAM;KACtB,MAAM,KAAK,IAAI,GAAG;KAClB,KAAK,IAAI,EAAE;KACX,MAAM,QAAQ,KAAK,IAAI,EAAE;KACzB,KAAK,IAAI,IAAI,GAAG;KAChB,IACE,OAAO,SAAS,IAAI,QACpB,MAAM,GAAG,QAAQ,MAAM,IAAI,GAAG,QAAQ,KACtC,KAAK,UAAU,MAAM,KAAK,MAAM,KAAK,UAAU,IAAI,KAAK,GAExD;KACF,UAAU;KACV,QAAQ;MACN,aAAa,IAAI;MACjB,QAAQ,GAAG,IAAI,QAAQ,IAAI,MAAM;MACjC,MAAM,IAAI;MACV,IAAI,IAAI;KACV,CAAC;IACH;IACA,KAAK,MAAM,CAAC,IAAI,QAAQ,MAAM;KAC5B,IAAI,KAAK,IAAI,EAAE,GAAG;KAClB,KAAK,OAAO,EAAE;KACd,UAAU;KACV,QAAQ;MACN,aAAa,IAAI;MACjB,QAAQ,GAAG,IAAI,QAAQ,KAAK;MAC5B,MAAM,IAAI;MACV,oBAAI,IAAI,KAAK;KACf,CAAC;IACH;IACA,IAAI,SAAS,SAAS;SACjB,IAAI,YAAY,QACnB,WAAW,KAAK,IAAI,WAAW,GAAG,aAAa,aAAa;GAChE,QAAQ;IACN,WAAW,aAAa;GAC1B;EACF;CACF;CACA,IAAS;CACT,OAAO;EACL;EACA,MAAM;EACN,OAAO,OAAO;GACZ,KAAK,MAAM,CAAC,OAAO,UAAU,OAAO,QAAQ,MAAM,MAAM,GACtD,KAAK,IAAI,IAAI;IAAE,aAAa,MAAM;IAAa;GAAM,CAAC,GAAG;IACvD,aAAa,MAAM;IACnB;IACA;IACA,MAAM,MAAM;IACZ,IAAI,MAAM;GACZ,CAAC;GAEH,SAAS;EACX;EACA,OAAO;GACL,UAAU;GACV,SAAS,OAAO;GAChB,KAAK,MAAM;EACb;CACF;AACF"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as Clock, s as IdSource, t as A2Store } from "./store-
|
|
1
|
+
import { r as Clock, s as IdSource, t as A2Store } from "./store-CyLUy86v.js";
|
|
2
2
|
//#region src/store-redis-http.d.ts
|
|
3
3
|
type RedisHttpStoreOptions = {
|
|
4
4
|
/** REST endpoint, e.g. `process.env.UPSTASH_REDIS_REST_URL`. */
|
package/dist/store-redis-http.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { i as A2Error } from "./session-clear-DGI4jTQ5.js";
|
|
2
|
-
import { r as NOTIFY_TIMINGS } from "./internal-
|
|
3
|
-
import { t as defaultSleep } from "./store-polling-
|
|
2
|
+
import { r as NOTIFY_TIMINGS } from "./internal-CscSY7K_.js";
|
|
3
|
+
import { t as defaultSleep } from "./store-polling-7WJV0YWP.js";
|
|
4
4
|
import { n as SYSTEM_CLOCK, t as RANDOM_IDS } from "./store-N8PXxDAS.js";
|
|
5
|
-
import { t as createRedisNotifyStore } from "./store-redis-notify-
|
|
5
|
+
import { t as createRedisNotifyStore } from "./store-redis-notify-CM0AfLY0.js";
|
|
6
6
|
//#region src/redis-http-subscriptions.ts
|
|
7
7
|
function redisHttpSubscriptions({ url, token, onReconnect, fallback }) {
|
|
8
8
|
const subscriptions = /* @__PURE__ */ new Map();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { i as A2Error, r as sessionClearedError, s as supersededAttemptError, t as CLEAR_EVENT_TYPE } from "./session-clear-DGI4jTQ5.js";
|
|
2
|
-
import { _ as nullProtoRecord, r as NOTIFY_TIMINGS, y as stateTailReaders } from "./internal-
|
|
3
|
-
import { i as streamActivities, n as pollingStream, r as createStreamActivity, t as defaultSleep } from "./store-polling-
|
|
2
|
+
import { _ as nullProtoRecord, r as NOTIFY_TIMINGS, y as stateTailReaders } from "./internal-CscSY7K_.js";
|
|
3
|
+
import { i as streamActivities, n as pollingStream, r as createStreamActivity, t as defaultSleep } from "./store-polling-7WJV0YWP.js";
|
|
4
4
|
import { n as isSerializedEvent, r as parseSerializedEvent, t as bufferedEvents } from "./stream-buffer-Cx7AAPGq.js";
|
|
5
5
|
import { t as idempotentReplay } from "./idempotent-replay-JdgMQRRm.js";
|
|
6
6
|
import { t as decodeReturnedEventIds } from "./store-codec-DTG0Ftek.js";
|
|
7
|
-
import { t as pollPresence } from "./store-presence-polling-
|
|
7
|
+
import { t as pollPresence } from "./store-presence-polling-B1ixeqIS.js";
|
|
8
8
|
//#region src/presence-recovery.ts
|
|
9
9
|
const key = ({ participant, field }) => JSON.stringify([participant, field]);
|
|
10
10
|
function presenceRecovery({ read, deliver, isActive }) {
|
|
@@ -464,7 +464,7 @@ return { 'ok', tostring(base + 1), pending_after }
|
|
|
464
464
|
/**
|
|
465
465
|
* KEYS: counter, meta, pending, ready, event snapshot pins, snapshot pin counts,
|
|
466
466
|
* metadata split.
|
|
467
|
-
* ARGV: idx, attempt, error, maxFailures, nowMs.
|
|
467
|
+
* ARGV: idx, attempt, error, maxFailures, nowMs, retryAtMs ('' for none).
|
|
468
468
|
*/
|
|
469
469
|
const FAIL_ATTEMPT_LUA = `
|
|
470
470
|
local COUNTER, META, SPLIT = KEYS[1], KEYS[2], KEYS[7]
|
|
@@ -496,8 +496,14 @@ put(meta_key, field .. ':e', ARGV[3])
|
|
|
496
496
|
put(meta_key, field .. ':lf', ARGV[5])
|
|
497
497
|
put(meta_key, field .. ':lfa', ARGV[2])
|
|
498
498
|
if dead then put(meta_key, field .. ':f', ARGV[5]) end
|
|
499
|
+
local hold = not dead and ARGV[6] ~= ''
|
|
500
|
+
if hold then put(meta_key, field .. ':ce', ARGV[6]) end
|
|
499
501
|
flush()
|
|
500
|
-
|
|
502
|
+
if hold then
|
|
503
|
+
redis.call('HDEL', meta_key, field .. ':ch')
|
|
504
|
+
else
|
|
505
|
+
redis.call('HDEL', meta_key, field .. ':ch', field .. ':ce')
|
|
506
|
+
end
|
|
501
507
|
if dead then
|
|
502
508
|
redis.call('ZREM', KEYS[4], field)
|
|
503
509
|
release_snapshot_pins(KEYS[5], KEYS[6])
|
|
@@ -506,23 +512,29 @@ end
|
|
|
506
512
|
return { 'failed', tostring(failures) }
|
|
507
513
|
`;
|
|
508
514
|
/**
|
|
509
|
-
* KEYS: store, counter, meta, pending, ready, metadata split
|
|
510
|
-
*
|
|
515
|
+
* KEYS: store, counter, meta, pending, ready, metadata split, snapshot pin
|
|
516
|
+
* counts.
|
|
517
|
+
* ARGV: holder, nowMs, expiresAtMs, excludedCount, excluded indexes, then
|
|
518
|
+
* maxFailures ('' for none) and the event snapshot-pins key prefix.
|
|
511
519
|
* The ready set is a subset of the pending set, so an empty ready set is
|
|
512
520
|
* enough to report 'settled'. A claimed result ends with the clear boundary.
|
|
513
521
|
*/
|
|
514
522
|
const CLAIM_AVAILABLE_LUA = `
|
|
515
523
|
local COUNTER, META, SPLIT = KEYS[2], KEYS[3], KEYS[6]
|
|
516
524
|
${META_LUA}
|
|
525
|
+
${RELEASE_PINS_LUA}
|
|
517
526
|
local ready = redis.call('ZRANGE', KEYS[5], 0, -1)
|
|
518
527
|
local excluded = {}
|
|
528
|
+
local tail = 5 + tonumber(ARGV[4])
|
|
519
529
|
for i = 1, tonumber(ARGV[4]) do excluded[ARGV[4 + i]] = true end
|
|
530
|
+
local max_failures = tonumber(ARGV[tail])
|
|
520
531
|
local candidates = {}
|
|
521
532
|
for _, field in ipairs(ready) do
|
|
522
533
|
if not excluded[field] then candidates[#candidates + 1] = field end
|
|
523
534
|
end
|
|
524
535
|
local rows = read_fields(candidates, { 'ce', 'd', 'fc', 'a', 'e', 'lf', 'lfa' })
|
|
525
536
|
local claimed = {}
|
|
537
|
+
local dead = {}
|
|
526
538
|
local retry_at = nil
|
|
527
539
|
for _, field in ipairs(candidates) do
|
|
528
540
|
local row = rows[field]
|
|
@@ -532,29 +544,63 @@ for _, field in ipairs(candidates) do
|
|
|
532
544
|
else
|
|
533
545
|
local entries = redis.call('XRANGE', KEYS[1], field .. '-0', field .. '-0')
|
|
534
546
|
if #entries == 0 then return { 'missing', field } end
|
|
535
|
-
local attempt = tostring(tonumber(row[2] or '0') + 1)
|
|
536
|
-
local first_claimed = row[3] or ARGV[2]
|
|
537
547
|
local meta_key = mkey(field)
|
|
548
|
+
local attempt = tostring(tonumber(row[2] or '0') + 1)
|
|
549
|
+
-- An expiry that is not the current attempt's retry hold is a lapsed
|
|
550
|
+
-- claim: its attempt never finished.
|
|
551
|
+
local lapsed = row[1] and row[7] ~= row[2]
|
|
552
|
+
local failures = tonumber(row[4] or '0')
|
|
553
|
+
if lapsed then
|
|
554
|
+
failures = failures + 1
|
|
555
|
+
put(meta_key, field .. ':a', tostring(failures))
|
|
556
|
+
end
|
|
538
557
|
put(meta_key, field .. ':d', attempt)
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
558
|
+
if lapsed and max_failures and failures >= max_failures then
|
|
559
|
+
-- That takeover spent the last failed attempt: dead-letter, unclaimed.
|
|
560
|
+
-- Advancing the attempt fences the lapsed one; nothing runs.
|
|
561
|
+
put(meta_key, field .. ':f', ARGV[2])
|
|
562
|
+
dead[#dead + 1] = field
|
|
563
|
+
claimed[#claimed + 1] = {
|
|
564
|
+
attempt,
|
|
565
|
+
tostring(failures),
|
|
566
|
+
row[5] or false,
|
|
567
|
+
row[3] or false,
|
|
568
|
+
read_fields({ field }, { 'lc' })[field][1] or false,
|
|
569
|
+
row[6] or false,
|
|
570
|
+
row[7] or false,
|
|
571
|
+
false,
|
|
572
|
+
false,
|
|
573
|
+
entries[1],
|
|
574
|
+
ARGV[2]
|
|
575
|
+
}
|
|
576
|
+
else
|
|
577
|
+
local first_claimed = row[3] or ARGV[2]
|
|
578
|
+
put(meta_key, field .. ':fc', first_claimed)
|
|
579
|
+
put(meta_key, field .. ':lc', ARGV[2])
|
|
580
|
+
put(meta_key, field .. ':ch', ARGV[1])
|
|
581
|
+
put(meta_key, field .. ':ce', ARGV[3])
|
|
582
|
+
claimed[#claimed + 1] = {
|
|
583
|
+
attempt,
|
|
584
|
+
tostring(failures),
|
|
585
|
+
row[5] or false,
|
|
586
|
+
first_claimed,
|
|
587
|
+
ARGV[2],
|
|
588
|
+
row[6] or false,
|
|
589
|
+
row[7] or false,
|
|
590
|
+
ARGV[1],
|
|
591
|
+
ARGV[3],
|
|
592
|
+
entries[1],
|
|
593
|
+
false
|
|
594
|
+
}
|
|
595
|
+
end
|
|
555
596
|
end
|
|
556
597
|
end
|
|
557
598
|
flush()
|
|
599
|
+
for _, field in ipairs(dead) do
|
|
600
|
+
redis.call('HDEL', mkey(field), field .. ':ch', field .. ':ce')
|
|
601
|
+
redis.call('ZREM', KEYS[5], field)
|
|
602
|
+
release_snapshot_pins(ARGV[tail + 1] .. field, KEYS[7])
|
|
603
|
+
end
|
|
558
604
|
if #claimed > 0 then
|
|
559
605
|
local result = { 'claimed', tostring(#claimed) }
|
|
560
606
|
for _, claim in ipairs(claimed) do
|
|
@@ -1268,7 +1314,7 @@ const toClaimAvailableResult = (sessionId, reply) => {
|
|
|
1268
1314
|
const count = Number(reply[1]);
|
|
1269
1315
|
const events = [];
|
|
1270
1316
|
for (let i = 0; i < count; i++) {
|
|
1271
|
-
const offset = 2 + i *
|
|
1317
|
+
const offset = 2 + i * 11;
|
|
1272
1318
|
const entry = reply[offset + 9];
|
|
1273
1319
|
const event = toEvent(sessionId, entry);
|
|
1274
1320
|
const fields = fieldMap(entry[1]);
|
|
@@ -1279,18 +1325,18 @@ const toClaimAvailableResult = (sessionId, reply) => {
|
|
|
1279
1325
|
processedByAttempt: null,
|
|
1280
1326
|
returnedEventIds: null,
|
|
1281
1327
|
firstClaimedAt: reply[offset + 3] === null ? null : new Date(Number(reply[offset + 3])),
|
|
1282
|
-
lastClaimedAt: new Date(Number(reply[offset + 4])),
|
|
1328
|
+
lastClaimedAt: reply[offset + 4] === null ? null : new Date(Number(reply[offset + 4])),
|
|
1283
1329
|
attemptCount: Number(reply[offset]),
|
|
1284
|
-
claimHolder: String(reply[offset + 7]),
|
|
1285
|
-
claimExpiresAt: new Date(Number(reply[offset + 8])),
|
|
1330
|
+
claimHolder: reply[offset + 7] === null ? null : String(reply[offset + 7]),
|
|
1331
|
+
claimExpiresAt: reply[offset + 8] === null ? null : new Date(Number(reply[offset + 8])),
|
|
1286
1332
|
failureCount: Number(reply[offset + 1]),
|
|
1287
1333
|
lastFailedAt: reply[offset + 5] === null ? null : new Date(Number(reply[offset + 5])),
|
|
1288
1334
|
lastFailedAttempt: reply[offset + 6] === null ? null : Number(reply[offset + 6]),
|
|
1289
1335
|
lastError: reply[offset + 2] === null ? null : String(reply[offset + 2]),
|
|
1290
|
-
failedAt: null
|
|
1336
|
+
failedAt: reply[offset + 10] === null ? null : new Date(Number(reply[offset + 10]))
|
|
1291
1337
|
}));
|
|
1292
1338
|
}
|
|
1293
|
-
const clearIndex = Number(reply[2 + count *
|
|
1339
|
+
const clearIndex = Number(reply[2 + count * 11] ?? 0);
|
|
1294
1340
|
if (clearIndex > 0) for (const event of events) event.clearIndex = clearIndex;
|
|
1295
1341
|
return {
|
|
1296
1342
|
outcome: "claimed",
|
|
@@ -1599,7 +1645,7 @@ function createRedisStoreCore(options) {
|
|
|
1599
1645
|
return readEventRange(sessionId, Math.max(after, clearIndex - 1), Math.min(opts?.throughIndex ?? frontier, frontier));
|
|
1600
1646
|
}));
|
|
1601
1647
|
},
|
|
1602
|
-
async claimAvailable({ sessionId, holder, ttlMs, expiresAtMs, excludeIndexes }) {
|
|
1648
|
+
async claimAvailable({ sessionId, holder, ttlMs, expiresAtMs, excludeIndexes, maxFailures }) {
|
|
1603
1649
|
return wrap(async () => {
|
|
1604
1650
|
const now = clock.now().getTime();
|
|
1605
1651
|
const expiresAt = expiresAtMs ?? now + ttlMs;
|
|
@@ -1610,13 +1656,16 @@ function createRedisStoreCore(options) {
|
|
|
1610
1656
|
metaKey(sessionId),
|
|
1611
1657
|
pendingKey(sessionId),
|
|
1612
1658
|
readyKey(sessionId),
|
|
1613
|
-
metaSplitKey(sessionId)
|
|
1659
|
+
metaSplitKey(sessionId),
|
|
1660
|
+
snapshotPinCountsKey(sessionId)
|
|
1614
1661
|
], [
|
|
1615
1662
|
holder,
|
|
1616
1663
|
now,
|
|
1617
1664
|
expiresAt,
|
|
1618
1665
|
excluded.length,
|
|
1619
|
-
...excluded
|
|
1666
|
+
...excluded,
|
|
1667
|
+
maxFailures ?? "",
|
|
1668
|
+
snapshotEventPinsPrefix(sessionId)
|
|
1620
1669
|
]);
|
|
1621
1670
|
return toClaimAvailableResult(sessionId, reply);
|
|
1622
1671
|
});
|
|
@@ -1727,8 +1776,9 @@ function createRedisStoreCore(options) {
|
|
|
1727
1776
|
throw new TypeError(`unexpected completion outcome '${outcome}'`);
|
|
1728
1777
|
});
|
|
1729
1778
|
},
|
|
1730
|
-
async failAttempt({ sessionId, index, attempt, error, maxFailures }) {
|
|
1779
|
+
async failAttempt({ sessionId, index, attempt, error, maxFailures, retryAfterMs }) {
|
|
1731
1780
|
return wrap(async () => {
|
|
1781
|
+
const now = clock.now().getTime();
|
|
1732
1782
|
const reply = await evalScript(FAIL_ATTEMPT_LUA, [
|
|
1733
1783
|
countKey(sessionId),
|
|
1734
1784
|
metaKey(sessionId),
|
|
@@ -1742,7 +1792,8 @@ function createRedisStoreCore(options) {
|
|
|
1742
1792
|
attempt,
|
|
1743
1793
|
error,
|
|
1744
1794
|
maxFailures,
|
|
1745
|
-
|
|
1795
|
+
now,
|
|
1796
|
+
retryAfterMs === void 0 ? "" : now + retryAfterMs
|
|
1746
1797
|
]);
|
|
1747
1798
|
const outcome = reply[0];
|
|
1748
1799
|
if (outcome === "cleared") return {
|
|
@@ -2490,4 +2541,4 @@ function createRedisNotifyStore(options) {
|
|
|
2490
2541
|
//#endregion
|
|
2491
2542
|
export { createRedisNotifyStore as t };
|
|
2492
2543
|
|
|
2493
|
-
//# sourceMappingURL=store-redis-notify-
|
|
2544
|
+
//# sourceMappingURL=store-redis-notify-CM0AfLY0.js.map
|