@nylorun/runtime 0.42.0-beta → 0.44.0-beta

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.
@@ -43,7 +43,11 @@
43
43
  * the delivery after commit, sends), and configs of tasks long finished are deleted. A push
44
44
  * row that fails is retried with the Host tuning's `a2a.pushRetry` and dropped once it is
45
45
  * `a2a.pushMaxAgeMs` old, never parked: the change feed covers what it said.
46
- * 7. **Hooks.** Callbacks registered with `ctx.onSweep`.
46
+ * 7. **Queued messages** (Host feature `queue-recovery`): at most every `sweep.queueRetryMs`, the
47
+ * turn start of every session queue an Agent's refusal left waiting is tried again
48
+ * (`retryQueuedStarts`); a message past the Runtime limit `queuedStartMs` fails
49
+ * (`queue.failed`). The end of a disk copy tries its Agent's sessions at once.
50
+ * 8. **Hooks.** Callbacks registered with `ctx.onSweep`.
47
51
  *
48
52
  * Every step runs one transaction per session it changes (a linked agent and its workflow
49
53
  * share one, child first), so the sweep follows the lock order in `store/types.ts`. A failing
@@ -51,12 +55,14 @@
51
55
  * reports it.
52
56
  */
53
57
  import { sweepUnusedAgents } from "./agents.js";
58
+ import { retryQueuedStarts } from "./commands.js";
54
59
  import { reconcileTriggers } from "./triggers.js";
55
60
  import { streamMissedRuns } from "./runs-stream.js";
56
61
  import { sweepPendingSeeds } from "../artifacts/disk.js";
57
62
  import { pendingAgentEffects, reconcilePendingAgentEffect, } from "../core/flow-host.js";
58
63
  import { hostTuning } from "../tuning.js";
59
- import { sweepStartChecks } from "./agent-versions.js";
64
+ import { idleMsOf, sweepStartChecks } from "./agent-versions.js";
65
+ import { readSandboxConfig } from "../sandbox/tenant-config.js";
60
66
  import { pumpPushes, pushRetry } from "../api/a2a/push.js";
61
67
  /*
62
68
  * The sweep's timings are the Host tuning's `sweep` group (`tuning.ts`):
@@ -69,6 +75,7 @@ import { pumpPushes, pushRetry } from "../api/a2a/push.js";
69
75
  * - `drainBudgetMs`: how long one pass may spend draining the outbox, and paging through
70
76
  * orphaned sessions. A backlog is worked off over several passes rather than holding one (and
71
77
  * with it the Tenant's sweep object in the execution) for long.
78
+ * - `queueRetryMs`: how often the queues an Agent's refusal left waiting are tried again.
72
79
  * - `batchSize`, `signalRetentionMs`, `outboxAttempts`, `outboxRetry`, `stalePodMs`.
73
80
  */
74
81
  /**
@@ -88,6 +95,7 @@ export async function sweep(ctx) {
88
95
  pass.orphansAfter !== undefined ||
89
96
  now.getTime() - pass.orphansAt >= hostTuning().sweep.orphanScanMs;
90
97
  const checkPods = pass.podsAt === undefined || now.getTime() - pass.podsAt >= hostTuning().sweep.orphanScanMs;
98
+ const retryQueues = pass.queuesAt === undefined || now.getTime() - pass.queuesAt >= hostTuning().sweep.queueRetryMs;
91
99
  const steps = [
92
100
  ["outbox", () => deliverOutbox(ctx, first ? 0 : hostTuning().sweep.outboxGraceMs)],
93
101
  ["linked", () => reconcileLinkedAgents(ctx)],
@@ -142,6 +150,17 @@ export async function sweep(ctx) {
142
150
  "signals",
143
151
  () => ctx.store.tx((t) => t.pruneSignals(new Date(now.getTime() - hostTuning().sweep.signalRetentionMs))),
144
152
  ],
153
+ ...(retryQueues
154
+ ? [
155
+ [
156
+ "queues",
157
+ async () => {
158
+ pass.queuesAt = now.getTime();
159
+ await retryQueuedStarts(ctx, { now, batchSize: hostTuning().sweep.batchSize });
160
+ },
161
+ ],
162
+ ]
163
+ : []),
145
164
  ...[...ctx.sweepHooks].map((hook) => ["hook", hook]),
146
165
  ];
147
166
  let failure;
@@ -287,7 +306,8 @@ export async function wakeOrphanedSessions(ctx, now = new Date(), after, budgetM
287
306
  }
288
307
  /**
289
308
  * Pod sandboxes (F7.2) whose change has not finished (creating, deleting, an old volume still
290
- * to delete, an expiry not yet recorded), or that should run but whose engine is not connected,
309
+ * to delete, an expiry not yet recorded), that should run but whose engine is not connected, or
310
+ * that run past their idle limit (a wake that armed no idle timer: the reconcile arms it),
291
311
  * and whose row has not moved for `sweep.stalePodMs` (a minute), get a reconcile: a pod or volume deleted outside
292
312
  * the Runtime is found, and a change goes on whose reconcile the execution itself lost (its
293
313
  * retry timer, an invocation an operator killed, Restate's state wiped) or whose outbox row
@@ -296,18 +316,27 @@ export async function wakeOrphanedSessions(ctx, now = new Date(), after, budgetM
296
316
  async function reconcileStalePods(ctx, now) {
297
317
  if (!ctx.pods)
298
318
  return;
299
- const stale = await ctx.store.tx(async (t) => (await t.listEnvironments()).filter((row) => {
300
- const pod = row.pod;
301
- if (!pod || now.getTime() - Date.parse(row.updatedAt) < hostTuning().sweep.stalePodMs)
302
- return false;
303
- return (pod.desired === "deleted" ||
304
- pod.retiring !== undefined ||
305
- pod.observed === "creating" ||
306
- pod.observed === "deleting" ||
307
- (pod.desired === "suspended" && pod.observed !== "suspended") ||
308
- // Running, but its engine is not connected: the pod may be gone, or its volume.
309
- (pod.desired === "running" && pod.observed === "running" && !ctx.harness.hosting(row.id)));
310
- }));
319
+ const stale = await ctx.store.tx(async (t) => {
320
+ const config = await readSandboxConfig(t);
321
+ return (await t.listEnvironments()).filter((row) => {
322
+ const pod = row.pod;
323
+ if (!pod || now.getTime() - Date.parse(row.updatedAt) < hostTuning().sweep.stalePodMs)
324
+ return false;
325
+ return (pod.desired === "deleted" ||
326
+ pod.retiring !== undefined ||
327
+ pod.observed === "creating" ||
328
+ pod.observed === "deleting" ||
329
+ (pod.desired === "suspended" && pod.observed !== "suspended") ||
330
+ // Running, but its engine is not connected: the pod may be gone, or its volume.
331
+ (pod.desired === "running" && pod.observed === "running" && !ctx.harness.hosting(row.id)) ||
332
+ // Running past its idle limit: its idle timer is missing (or a turn holds it, which the
333
+ // reconcile leaves alone).
334
+ (pod.desired === "running" &&
335
+ pod.observed === "running" &&
336
+ now.getTime() - Date.parse(pod.lastActiveAt ?? row.createdAt) >
337
+ idleMsOf(config, row) + hostTuning().sweep.stalePodMs));
338
+ });
339
+ });
311
340
  for (const row of stale)
312
341
  await ctx.sandboxSignal(row.id, { kind: "reconcile" });
313
342
  }
package/dist/tuning.d.ts CHANGED
@@ -121,6 +121,7 @@ export declare const HostTuningSchema: z.ZodObject<{
121
121
  maxMs: z.ZodDefault<z.ZodNumber>;
122
122
  }, z.core.$strict>>;
123
123
  stalePodMs: z.ZodDefault<z.ZodNumber>;
124
+ queueRetryMs: z.ZodDefault<z.ZodNumber>;
124
125
  }, z.core.$strict>>;
125
126
  a2a: z.ZodPrefault<z.ZodObject<{
126
127
  pushRetry: z.ZodPrefault<z.ZodObject<{
@@ -297,6 +298,8 @@ export declare const HostTuningSchema: z.ZodObject<{
297
298
  networkProbeMs: z.ZodDefault<z.ZodNumber>;
298
299
  networkPauseMs: z.ZodDefault<z.ZodNumber>;
299
300
  networkConfirmations: z.ZodDefault<z.ZodNumber>;
301
+ wakeNetworkProbeMs: z.ZodDefault<z.ZodNumber>;
302
+ wakeNetworkConfirmations: z.ZodDefault<z.ZodNumber>;
300
303
  setupRetryPollMs: z.ZodDefault<z.ZodNumber>;
301
304
  setupAfterSeedPollMs: z.ZodDefault<z.ZodNumber>;
302
305
  setupReportTailChars: z.ZodDefault<z.ZodNumber>;
package/dist/tuning.js CHANGED
@@ -207,6 +207,11 @@ export const HostTuningSchema = z
207
207
  outboxRetry: backoff(5_000, 10 * MINUTE),
208
208
  /** How long a pod row may go unchanged before the sweep checks it. */
209
209
  stalePodMs: ms(MINUTE),
210
+ /**
211
+ * How often the sweep tries again the turn start of queued messages their Agent refused
212
+ * (Host feature `queue-recovery`); they fail after the Runtime limit `queuedStartMs`.
213
+ */
214
+ queueRetryMs: ms(30_000),
210
215
  }),
211
216
  /** The A2A server's push notifications (Host feature `a2a-profile-v2`). */
212
217
  a2a: group({
@@ -495,6 +500,13 @@ export const HostTuningSchema = z
495
500
  networkProbeMs: ms(1_000),
496
501
  networkPauseMs: ms(250, 0),
497
502
  networkConfirmations: count(3),
503
+ /**
504
+ * The same check on a wake (the disk already holds the engine's volume id): each probe, and
505
+ * the failed probes in a row that prove an address blocked. A probe that connects turns the
506
+ * wake's check into the full one.
507
+ */
508
+ wakeNetworkProbeMs: ms(150),
509
+ wakeNetworkConfirmations: count(1),
498
510
  /** Environment setup: how often a failed setup is checked for a retry, and after a seed. */
499
511
  setupRetryPollMs: ms(5_000),
500
512
  setupAfterSeedPollMs: ms(1_000),
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const RUNTIME_VERSION = "0.42.0-beta";
1
+ export declare const RUNTIME_VERSION = "0.44.0-beta";
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  // Kept in step with package.json by runtime/server/scripts/check-package.mjs, which runs in npm run check.
2
2
  // release:prepare also rewrites this when it bumps @nylorun/runtime.
3
- export const RUNTIME_VERSION = "0.42.0-beta";
3
+ export const RUNTIME_VERSION = "0.44.0-beta";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nylorun/runtime",
3
- "version": "0.42.0-beta",
3
+ "version": "0.44.0-beta",
4
4
  "description": "Nylorun Runtime: the agent execution Host on Postgres, Restate and S2, and model providers.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -65,8 +65,8 @@
65
65
  "@hono/node-server": "^2.1.5",
66
66
  "@hono/zod-openapi": "^1.6.3",
67
67
  "@modelcontextprotocol/sdk": "^1.32.1",
68
- "@nylorun/core": "0.36.0-beta",
69
- "@nylorun/harness": "0.33.0-beta",
68
+ "@nylorun/core": "0.38.0-beta",
69
+ "@nylorun/harness": "0.34.1-beta",
70
70
  "@restatedev/restate-sdk": "1.17.3",
71
71
  "@restatedev/restate-sdk-clients": "1.17.3",
72
72
  "@s2-dev/streamstore": "0.28.0",