@ricsam/r5d-worker 0.0.110 → 0.0.111
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/README.md +12 -0
- package/dist/cjs/job-resources.cjs +335 -0
- package/dist/cjs/main.cjs +123 -25
- package/dist/cjs/package.json +1 -1
- package/dist/mjs/job-resources.mjs +293 -0
- package/dist/mjs/main.mjs +127 -25
- package/dist/mjs/package.json +1 -1
- package/dist/types/job-resources.d.ts +61 -0
- package/package.json +1 -1
package/dist/cjs/main.cjs
CHANGED
|
@@ -62,6 +62,7 @@ var import_plan_lint = require("./plan-lint.cjs");
|
|
|
62
62
|
var import_node_fs = __toESM(require("node:fs"), 1);
|
|
63
63
|
var import_recovery_store = require("./recovery-store.cjs");
|
|
64
64
|
var import_recovery_output_window = require("./recovery-output-window.cjs");
|
|
65
|
+
var import_job_resources = require("./job-resources.cjs");
|
|
65
66
|
var import_recovery_protocol = require("./recovery-protocol.cjs");
|
|
66
67
|
var import_node_path = __toESM(require("node:path"), 1);
|
|
67
68
|
var import_node_crypto = require("node:crypto");
|
|
@@ -154,6 +155,7 @@ const PTY_INPUT_BUSY_GRACE_MS = 3e3;
|
|
|
154
155
|
const PTY_FOREGROUND_POLL_MS = 1e3;
|
|
155
156
|
const PTY_FOREGROUND_IDLE_ENABLED = process.env.R5D_PTY_FOREGROUND_IDLE !== "0";
|
|
156
157
|
const PTY_TMP_PATH_PREFIX = "r5d-worker-tmp://";
|
|
158
|
+
let workerJobResources;
|
|
157
159
|
const activeProcesses = /* @__PURE__ */ new Map();
|
|
158
160
|
const credentialBearingProcessGroups = /* @__PURE__ */ new Map();
|
|
159
161
|
const credentialBearingProcessGroupTargets = /* @__PURE__ */ new Map();
|
|
@@ -202,8 +204,23 @@ function renewWorkerExecutionLease(leaseMs) {
|
|
|
202
204
|
() => {
|
|
203
205
|
if (Date.now() < workerExecutionLeaseDeadline) return;
|
|
204
206
|
workerLeaseExpired = true;
|
|
207
|
+
try {
|
|
208
|
+
workerJobResources?.cancelMatching((id) => id.startsWith("pty:"));
|
|
209
|
+
} catch (error) {
|
|
210
|
+
process.stderr.write(`[r5d-worker] expired PTY resource termination failed: ${error}
|
|
211
|
+
`);
|
|
212
|
+
}
|
|
213
|
+
closeAllPtys();
|
|
205
214
|
for (const operation of recoveryStore?.operations() ?? []) {
|
|
206
|
-
if (operation.sessionId && operation.state !== "completed")
|
|
215
|
+
if (operation.sessionId && operation.state !== "completed") {
|
|
216
|
+
recoveryStore?.cancelSession(operation.sessionId);
|
|
217
|
+
try {
|
|
218
|
+
workerJobResources?.cancelSession(operation.sessionId);
|
|
219
|
+
} catch (error) {
|
|
220
|
+
process.stderr.write(`[r5d-worker] expired command resource termination failed: ${error}
|
|
221
|
+
`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
207
224
|
}
|
|
208
225
|
for (const [runId, active] of activeProcesses) {
|
|
209
226
|
if (!active.sessionId) continue;
|
|
@@ -1597,7 +1614,7 @@ function credentialReapContractStatus(probe) {
|
|
|
1597
1614
|
if (process.platform !== "linux") return "direct";
|
|
1598
1615
|
try {
|
|
1599
1616
|
const cgroupText = import_node_fs.default.readFileSync("/proc/self/cgroup", "utf8");
|
|
1600
|
-
const unit =
|
|
1617
|
+
const unit = /(?:^|\/)r5d-worker\.service(?:\/|$|\n)/m.test(cgroupText) ? "r5d-worker.service" : void 0;
|
|
1601
1618
|
if (unit !== "r5d-worker.service") {
|
|
1602
1619
|
return SYSTEMD_INVOCATION_IDENTIFIER_PATTERN.test(process.env.INVOCATION_ID ?? "") ? "systemd_unverified" : "direct";
|
|
1603
1620
|
}
|
|
@@ -1631,7 +1648,7 @@ function credentialReapContractStatus(probe) {
|
|
|
1631
1648
|
}
|
|
1632
1649
|
}
|
|
1633
1650
|
if (resolved.platform !== "linux") return "direct";
|
|
1634
|
-
if (!/(?:^|\/)r5d-worker\.service(
|
|
1651
|
+
if (!/(?:^|\/)r5d-worker\.service(?:\/|$|\n)/m.test(resolved.cgroupText)) {
|
|
1635
1652
|
return SYSTEMD_INVOCATION_IDENTIFIER_PATTERN.test(resolved.invocationId ?? "") ? "systemd_unverified" : "direct";
|
|
1636
1653
|
}
|
|
1637
1654
|
if (!SYSTEMD_INVOCATION_IDENTIFIER_PATTERN.test(resolved.invocationId ?? "")) return "systemd_unverified";
|
|
@@ -2013,12 +2030,6 @@ function resolveCommandCwd(branchPath, cwd) {
|
|
|
2013
2030
|
}
|
|
2014
2031
|
return resolved;
|
|
2015
2032
|
}
|
|
2016
|
-
async function collectStream(stream) {
|
|
2017
|
-
if (!stream) {
|
|
2018
|
-
return "";
|
|
2019
|
-
}
|
|
2020
|
-
return await new Response(stream).text();
|
|
2021
|
-
}
|
|
2022
2033
|
async function streamCommandOutput(stream, onData) {
|
|
2023
2034
|
if (!stream) {
|
|
2024
2035
|
return;
|
|
@@ -2739,8 +2750,37 @@ async function prepareShellEnvForTarget(input) {
|
|
|
2739
2750
|
...targetProcessEnv(input.rootDir, input.target)
|
|
2740
2751
|
};
|
|
2741
2752
|
}
|
|
2753
|
+
async function releaseWorkerJobResources(resources) {
|
|
2754
|
+
if (!resources) return;
|
|
2755
|
+
try {
|
|
2756
|
+
await resources.release();
|
|
2757
|
+
} catch (error) {
|
|
2758
|
+
process.stderr.write(`[r5d-worker] job resource cleanup failed: ${error instanceof Error ? error.message : String(error)}
|
|
2759
|
+
`);
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
async function acquireWorkerCommandResources(ws, message, assertAdmission) {
|
|
2763
|
+
const id = message.type === "pty_open" ? `pty:${message.ptyId}` : message.runId;
|
|
2764
|
+
const operationId = message.type === "pty_open" ? id : `exec:${id}`;
|
|
2765
|
+
sendWorkerMessage(ws, { type: "heartbeat_lease", operationId, active: true });
|
|
2766
|
+
try {
|
|
2767
|
+
return await workerJobResources.acquire({
|
|
2768
|
+
id,
|
|
2769
|
+
lane: message.type === "exec" && message.workspaceEffect === "none" ? "utility" : "general",
|
|
2770
|
+
..."sessionId" in message && message.sessionId ? { sessionId: message.sessionId } : {},
|
|
2771
|
+
assertAdmission: () => {
|
|
2772
|
+
assertAdmission();
|
|
2773
|
+
if (cancelledProcessRuns.has(id)) throw new import_job_resources.WorkerJobCancelledError();
|
|
2774
|
+
}
|
|
2775
|
+
});
|
|
2776
|
+
} finally {
|
|
2777
|
+
sendWorkerMessage(ws, { type: "heartbeat_lease", operationId, active: false });
|
|
2778
|
+
}
|
|
2779
|
+
}
|
|
2742
2780
|
async function executeCommand(input) {
|
|
2743
2781
|
const startedAt = Date.now();
|
|
2782
|
+
const outputAbort = new AbortController();
|
|
2783
|
+
let outputReaders = [];
|
|
2744
2784
|
let timeout;
|
|
2745
2785
|
let spawnedProcess;
|
|
2746
2786
|
let preparationSettled = false;
|
|
@@ -2761,7 +2801,7 @@ async function executeCommand(input) {
|
|
|
2761
2801
|
});
|
|
2762
2802
|
const cwd = resolveCommandCwd(input.resolvedTarget.rootPath, input.message.cwd);
|
|
2763
2803
|
input.assertAdmission();
|
|
2764
|
-
const subprocess = Bun.spawn(input.message.argv, {
|
|
2804
|
+
const subprocess = Bun.spawn(input.resources.wrap(input.message.argv), {
|
|
2765
2805
|
cwd,
|
|
2766
2806
|
stdout: "pipe",
|
|
2767
2807
|
stderr: "pipe",
|
|
@@ -2789,6 +2829,7 @@ async function executeCommand(input) {
|
|
|
2789
2829
|
settlePreparation();
|
|
2790
2830
|
if (input.message.timeoutMs) {
|
|
2791
2831
|
timeout = setTimeout(() => {
|
|
2832
|
+
input.resources.kill();
|
|
2792
2833
|
void (0, import_process_tree.terminateProcessTree)(subprocess).catch((error) => {
|
|
2793
2834
|
process.stderr.write(
|
|
2794
2835
|
`[r5d-worker] failed to terminate timed-out command ${input.message.runId}: ${error instanceof Error ? error.message : String(error)}
|
|
@@ -2797,21 +2838,26 @@ async function executeCommand(input) {
|
|
|
2797
2838
|
});
|
|
2798
2839
|
}, input.message.timeoutMs);
|
|
2799
2840
|
}
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
]);
|
|
2841
|
+
outputReaders = [
|
|
2842
|
+
(0, import_job_resources.collectWorkerInlineOutput)(subprocess.stdout, void 0, outputAbort.signal),
|
|
2843
|
+
(0, import_job_resources.collectWorkerInlineOutput)(subprocess.stderr, void 0, outputAbort.signal)
|
|
2844
|
+
];
|
|
2845
|
+
const [stdout, stderr, exitCode] = await Promise.all([outputReaders[0], outputReaders[1], subprocess.exited]);
|
|
2805
2846
|
return {
|
|
2806
2847
|
type: "exec_result",
|
|
2807
2848
|
requestId: input.message.requestId,
|
|
2808
2849
|
stdout,
|
|
2809
2850
|
stderr,
|
|
2810
2851
|
exitCode,
|
|
2811
|
-
durationMs: Date.now() - startedAt
|
|
2852
|
+
durationMs: Date.now() - startedAt,
|
|
2853
|
+
...input.resources.memoryLimitExceeded() ? {
|
|
2854
|
+
error: `Command exceeded its worker memory limit (${input.resources.memoryBytes} bytes). Reduce parallelism or memory use and retry.`
|
|
2855
|
+
} : {}
|
|
2812
2856
|
};
|
|
2813
2857
|
} catch (error) {
|
|
2858
|
+
outputAbort.abort(error);
|
|
2814
2859
|
if (error instanceof StaleWorkerAdmissionError) throw error;
|
|
2860
|
+
input.resources.kill();
|
|
2815
2861
|
return {
|
|
2816
2862
|
type: "exec_result",
|
|
2817
2863
|
requestId: input.message.requestId,
|
|
@@ -2829,6 +2875,8 @@ async function executeCommand(input) {
|
|
|
2829
2875
|
if (spawnedProcess) {
|
|
2830
2876
|
await reapCompletedCredentialBearingProcessGroup(input.message.runId, spawnedProcess);
|
|
2831
2877
|
}
|
|
2878
|
+
outputAbort.abort();
|
|
2879
|
+
await Promise.allSettled(outputReaders);
|
|
2832
2880
|
activeProcesses.delete(input.message.runId);
|
|
2833
2881
|
}
|
|
2834
2882
|
}
|
|
@@ -2866,7 +2914,7 @@ async function executeStreamingCommand(input) {
|
|
|
2866
2914
|
const cwd = resolveCommandCwd(input.resolvedTarget.rootPath, input.message.cwd);
|
|
2867
2915
|
const interactive = input.message.interactive === true;
|
|
2868
2916
|
input.assertAdmission();
|
|
2869
|
-
const subprocess = Bun.spawn(input.message.argv, {
|
|
2917
|
+
const subprocess = Bun.spawn(input.resources.wrap(input.message.argv), {
|
|
2870
2918
|
cwd,
|
|
2871
2919
|
// Without an explicit stdin the process reads /dev/null and interactive
|
|
2872
2920
|
// prompts see immediate EOF; "pipe" keeps stdin open for exec_stdin.
|
|
@@ -2909,6 +2957,7 @@ async function executeStreamingCommand(input) {
|
|
|
2909
2957
|
if (input.message.timeoutMs) {
|
|
2910
2958
|
timeout = setTimeout(() => {
|
|
2911
2959
|
timedOut = true;
|
|
2960
|
+
input.resources.kill();
|
|
2912
2961
|
closeProcessStdin(activeProcesses.get(input.message.runId));
|
|
2913
2962
|
void (0, import_process_tree.terminateProcessTree)(subprocess).catch((error) => {
|
|
2914
2963
|
process.stderr.write(
|
|
@@ -2937,6 +2986,16 @@ async function executeStreamingCommand(input) {
|
|
|
2937
2986
|
});
|
|
2938
2987
|
})
|
|
2939
2988
|
]);
|
|
2989
|
+
if (input.resources.memoryLimitExceeded()) {
|
|
2990
|
+
sendWorkerMessage(input.ws, {
|
|
2991
|
+
type: "exec_output",
|
|
2992
|
+
runId: input.message.runId,
|
|
2993
|
+
stream: "stderr",
|
|
2994
|
+
data: `
|
|
2995
|
+
[r5d-worker] Command exceeded its memory limit (${input.resources.memoryBytes} bytes). Reduce parallelism or memory use and retry.
|
|
2996
|
+
`
|
|
2997
|
+
});
|
|
2998
|
+
}
|
|
2940
2999
|
const canonicalWorkspaceHead = canonicalSyncTerminalHead(input.resolvedTarget);
|
|
2941
3000
|
const terminal = {
|
|
2942
3001
|
type: "exec_exit",
|
|
@@ -3366,6 +3425,7 @@ async function openPty(input) {
|
|
|
3366
3425
|
}) : {};
|
|
3367
3426
|
const targetEnv = targetProcessEnv(input.rootDir, input.resolvedTarget.target);
|
|
3368
3427
|
const shell = resolveHostShell(input.message.command);
|
|
3428
|
+
const shellArgv = input.resources.wrap([shell.file, ...shell.args]);
|
|
3369
3429
|
const outputCoalescer = (0, import_pty_output_coalescer.createPtyOutputCoalescer)({
|
|
3370
3430
|
send: (data) => {
|
|
3371
3431
|
sendWorkerMessage(input.ws, {
|
|
@@ -3385,8 +3445,8 @@ async function openPty(input) {
|
|
|
3385
3445
|
};
|
|
3386
3446
|
try {
|
|
3387
3447
|
const ptyProcess = createNodePtyBridge({
|
|
3388
|
-
file:
|
|
3389
|
-
args:
|
|
3448
|
+
file: shellArgv[0],
|
|
3449
|
+
args: shellArgv.slice(1),
|
|
3390
3450
|
ptyOptions: {
|
|
3391
3451
|
name: "xterm-256color",
|
|
3392
3452
|
cols: Math.max(1, Math.min(Math.floor(input.message.cols || 80), 500)),
|
|
@@ -3415,11 +3475,18 @@ async function openPty(input) {
|
|
|
3415
3475
|
outputCoalescer.push(data);
|
|
3416
3476
|
},
|
|
3417
3477
|
onExit: (event) => {
|
|
3478
|
+
if (input.resources.memoryLimitExceeded())
|
|
3479
|
+
outputCoalescer.push(
|
|
3480
|
+
`\r
|
|
3481
|
+
[r5d-worker] Terminal exceeded its memory limit (${input.resources.memoryBytes} bytes). Reduce parallelism or memory use and retry.\r
|
|
3482
|
+
`
|
|
3483
|
+
);
|
|
3418
3484
|
outputCoalescer.flush();
|
|
3419
3485
|
input.releaseWorkspaceMutation?.();
|
|
3420
3486
|
activePtys.delete(input.message.ptyId);
|
|
3421
3487
|
cleanupEnvFiles();
|
|
3422
3488
|
input.onTerminal?.();
|
|
3489
|
+
void releaseWorkerJobResources(input.resources);
|
|
3423
3490
|
sendWorkerMessage(input.ws, {
|
|
3424
3491
|
type: "pty_exit",
|
|
3425
3492
|
ptyId: input.message.ptyId,
|
|
@@ -3433,6 +3500,7 @@ async function openPty(input) {
|
|
|
3433
3500
|
activePtys.delete(input.message.ptyId);
|
|
3434
3501
|
cleanupEnvFiles();
|
|
3435
3502
|
input.onTerminal?.();
|
|
3503
|
+
void releaseWorkerJobResources(input.resources);
|
|
3436
3504
|
sendWorkerMessage(input.ws, {
|
|
3437
3505
|
type: "pty_error",
|
|
3438
3506
|
requestId: input.message.requestId,
|
|
@@ -3482,6 +3550,7 @@ function resizePty(message) {
|
|
|
3482
3550
|
ptyProcess.resize(Math.max(1, Math.min(Math.floor(message.cols || 80), 500)), Math.max(1, Math.min(Math.floor(message.rows || 24), 500)));
|
|
3483
3551
|
}
|
|
3484
3552
|
function closePty(message) {
|
|
3553
|
+
workerJobResources?.cancel(`pty:${message.ptyId}`);
|
|
3485
3554
|
const ptyProcess = activePtys.get(message.ptyId);
|
|
3486
3555
|
if (!ptyProcess) {
|
|
3487
3556
|
return;
|
|
@@ -3500,7 +3569,7 @@ function closePtysBestEffort(ptys, reportFailure) {
|
|
|
3500
3569
|
function closeAllPtys() {
|
|
3501
3570
|
closePtysBestEffort(activePtys, (ptyId, error) => {
|
|
3502
3571
|
process.stderr.write(
|
|
3503
|
-
`[r5d-worker] failed to close PTY ${ptyId} after
|
|
3572
|
+
`[r5d-worker] failed to close PTY ${ptyId} after execution lease expiry: ${error instanceof Error ? error.message : String(error)}
|
|
3504
3573
|
`
|
|
3505
3574
|
);
|
|
3506
3575
|
});
|
|
@@ -3573,6 +3642,11 @@ async function startWorker(options, projectRuntime = {
|
|
|
3573
3642
|
initializeCredentialStoreDirectoryOnce();
|
|
3574
3643
|
const label = requireValue(options.label, "Missing required --label <label>");
|
|
3575
3644
|
validateLabel(label);
|
|
3645
|
+
if (!workerJobResources) {
|
|
3646
|
+
workerJobResources = (0, import_job_resources.createWorkerJobResources)();
|
|
3647
|
+
process.stdout.write(`[r5d-worker] job resources: ${workerJobResources.isolation}; ${JSON.stringify(workerJobResources.budget)}
|
|
3648
|
+
`);
|
|
3649
|
+
}
|
|
3576
3650
|
const rootDir = import_node_path.default.resolve(options.rootDir ?? process.env.R5D_ROOT ?? defaultRootDir());
|
|
3577
3651
|
recoveryStore ??= new import_recovery_store.WorkerRecoveryStore(
|
|
3578
3652
|
import_node_path.default.join(rootDir, ".worker-recovery", (0, import_node_crypto.createHash)("sha256").update(`${baseUrl}\0${label}`).digest("hex"), "protocol.sqlite")
|
|
@@ -5777,6 +5851,7 @@ async function startWorker(options, projectRuntime = {
|
|
|
5777
5851
|
}
|
|
5778
5852
|
if (message.type === "cancel_session") {
|
|
5779
5853
|
recoveryStore.cancelSession(message.sessionId);
|
|
5854
|
+
workerJobResources?.cancelSession(message.sessionId);
|
|
5780
5855
|
await Promise.all(
|
|
5781
5856
|
[...activeProcesses].filter(([, active]) => active.sessionId === message.sessionId).map(async ([runId, active]) => {
|
|
5782
5857
|
cancelledProcessRuns.add(runId);
|
|
@@ -6263,8 +6338,14 @@ async function startWorker(options, projectRuntime = {
|
|
|
6263
6338
|
return;
|
|
6264
6339
|
}
|
|
6265
6340
|
if (message.type === "cancel") {
|
|
6341
|
+
let resourceCancellationError;
|
|
6342
|
+
try {
|
|
6343
|
+
workerJobResources?.cancel(message.runId);
|
|
6344
|
+
} catch (error) {
|
|
6345
|
+
resourceCancellationError = error instanceof Error ? error.message : String(error);
|
|
6346
|
+
}
|
|
6266
6347
|
const active = activeProcesses.get(message.runId);
|
|
6267
|
-
let cancelled =
|
|
6348
|
+
let cancelled = resourceCancellationError === void 0;
|
|
6268
6349
|
let cancelMessage;
|
|
6269
6350
|
if (active) {
|
|
6270
6351
|
try {
|
|
@@ -6279,6 +6360,7 @@ async function startWorker(options, projectRuntime = {
|
|
|
6279
6360
|
cancelledProcessRuns.add(message.runId);
|
|
6280
6361
|
cancelMessage = "Cancellation queued before command start";
|
|
6281
6362
|
}
|
|
6363
|
+
if (resourceCancellationError) cancelMessage += `; job resource termination failed: ${resourceCancellationError}`;
|
|
6282
6364
|
sendSerializedWorkerMessage(
|
|
6283
6365
|
ws,
|
|
6284
6366
|
JSON.stringify({
|
|
@@ -6365,13 +6447,16 @@ async function startWorker(options, projectRuntime = {
|
|
|
6365
6447
|
});
|
|
6366
6448
|
return;
|
|
6367
6449
|
}
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
if (targetMayMutateVisibleWorkspace(message.target)) recordVisibleWorkspaceMutation(message.target);
|
|
6371
|
-
});
|
|
6450
|
+
let resources;
|
|
6451
|
+
let resourcesTransferred = false;
|
|
6372
6452
|
let releaseWorkspaceMutation;
|
|
6373
6453
|
let mutationLeaseTransferred = false;
|
|
6374
6454
|
try {
|
|
6455
|
+
resources = await acquireWorkerCommandResources(ws, message, assertMessageAdmission);
|
|
6456
|
+
await (0, import_workspace_command_sync_policy.reserveWorkspaceCommandAfterCurrentSync)(message.target, workspaceSyncSingleFlight, () => {
|
|
6457
|
+
workspaceSyncPriorityPtyTargets.set(message.ptyId, message.target);
|
|
6458
|
+
if (targetMayMutateVisibleWorkspace(message.target)) recordVisibleWorkspaceMutation(message.target);
|
|
6459
|
+
});
|
|
6375
6460
|
releaseWorkspaceMutation = await (0, import_workspace_command_sync_policy.acquireWorkspaceCommandMutation)(message.target, workspaceSyncSingleFlight);
|
|
6376
6461
|
if (workspaceOperationsAreFenced(deferredWorkspaceConfiguration, activeWorkspaceIncidentId)) {
|
|
6377
6462
|
throw new Error(
|
|
@@ -6382,6 +6467,7 @@ async function startWorker(options, projectRuntime = {
|
|
|
6382
6467
|
process.stdout.write(`[r5d-worker] pty ${message.ptyId}: ${describeWorkerSessionTarget(message.target)}
|
|
6383
6468
|
`);
|
|
6384
6469
|
await openPty({
|
|
6470
|
+
resources,
|
|
6385
6471
|
ws,
|
|
6386
6472
|
message,
|
|
6387
6473
|
resolvedTarget,
|
|
@@ -6394,6 +6480,7 @@ async function startWorker(options, projectRuntime = {
|
|
|
6394
6480
|
}
|
|
6395
6481
|
} : {}
|
|
6396
6482
|
});
|
|
6483
|
+
resourcesTransferred = true;
|
|
6397
6484
|
mutationLeaseTransferred = releaseWorkspaceMutation !== void 0;
|
|
6398
6485
|
} catch (error) {
|
|
6399
6486
|
sendWorkerMessageFromCurrentSource(ws, {
|
|
@@ -6405,6 +6492,7 @@ async function startWorker(options, projectRuntime = {
|
|
|
6405
6492
|
} finally {
|
|
6406
6493
|
workspaceSyncPriorityPtyTargets.delete(message.ptyId);
|
|
6407
6494
|
if (!mutationLeaseTransferred) releaseWorkspaceMutation?.();
|
|
6495
|
+
if (!resourcesTransferred) await releaseWorkerJobResources(resources);
|
|
6408
6496
|
}
|
|
6409
6497
|
return;
|
|
6410
6498
|
}
|
|
@@ -6463,9 +6551,11 @@ async function startWorker(options, projectRuntime = {
|
|
|
6463
6551
|
return;
|
|
6464
6552
|
}
|
|
6465
6553
|
let result;
|
|
6554
|
+
let resources;
|
|
6466
6555
|
let targetReserved = false;
|
|
6467
6556
|
const hasWorkspaceEffect = workerCommandHasWorkspaceEffect(message);
|
|
6468
6557
|
try {
|
|
6558
|
+
resources = await acquireWorkerCommandResources(ws, message, assertMessageAdmission);
|
|
6469
6559
|
if (hasWorkspaceEffect) {
|
|
6470
6560
|
await (0, import_workspace_command_sync_policy.reserveWorkspaceCommandAfterCurrentSync)(message.target, workspaceSyncSingleFlight, () => {
|
|
6471
6561
|
workspaceSyncPriorityProcessTargets.set(message.runId, message.target);
|
|
@@ -6483,6 +6573,7 @@ async function startWorker(options, projectRuntime = {
|
|
|
6483
6573
|
process.stdout.write(`[r5d-worker] exec ${message.runId}: ${message.argv.join(" ")}
|
|
6484
6574
|
`);
|
|
6485
6575
|
return await executeCommand({
|
|
6576
|
+
resources,
|
|
6486
6577
|
message,
|
|
6487
6578
|
resolvedTarget,
|
|
6488
6579
|
baseUrl,
|
|
@@ -6518,6 +6609,8 @@ async function startWorker(options, projectRuntime = {
|
|
|
6518
6609
|
};
|
|
6519
6610
|
} finally {
|
|
6520
6611
|
if (targetReserved) workspaceSyncPriorityProcessTargets.delete(message.runId);
|
|
6612
|
+
await releaseWorkerJobResources(resources);
|
|
6613
|
+
cancelledProcessRuns.delete(message.runId);
|
|
6521
6614
|
}
|
|
6522
6615
|
if (infrastructureStoppedRunIds.has(message.runId)) {
|
|
6523
6616
|
recoveryStore.unknown(message.requestId);
|
|
@@ -6549,12 +6642,14 @@ async function startWorker(options, projectRuntime = {
|
|
|
6549
6642
|
runId: message.runId
|
|
6550
6643
|
});
|
|
6551
6644
|
const hasWorkspaceEffect = workerCommandHasWorkspaceEffect(message);
|
|
6645
|
+
let resources;
|
|
6552
6646
|
const runCommand = async () => {
|
|
6553
6647
|
try {
|
|
6554
6648
|
const resolvedTarget = resolveMessageTarget(message.target);
|
|
6555
6649
|
process.stdout.write(`[r5d-worker] exec_start ${message.runId}: ${message.argv.join(" ")}
|
|
6556
6650
|
`);
|
|
6557
6651
|
await executeStreamingCommand({
|
|
6652
|
+
resources,
|
|
6558
6653
|
ws,
|
|
6559
6654
|
message,
|
|
6560
6655
|
resolvedTarget,
|
|
@@ -6588,6 +6683,7 @@ async function startWorker(options, projectRuntime = {
|
|
|
6588
6683
|
const execution = (async () => {
|
|
6589
6684
|
let targetReserved = false;
|
|
6590
6685
|
try {
|
|
6686
|
+
resources = await acquireWorkerCommandResources(ws, message, assertMessageAdmission);
|
|
6591
6687
|
if (hasWorkspaceEffect) {
|
|
6592
6688
|
await (0, import_workspace_command_sync_policy.reserveWorkspaceCommandAfterCurrentSync)(message.target, workspaceSyncSingleFlight, () => {
|
|
6593
6689
|
workspaceSyncPriorityProcessTargets.set(message.runId, message.target);
|
|
@@ -6603,6 +6699,8 @@ async function startWorker(options, projectRuntime = {
|
|
|
6603
6699
|
});
|
|
6604
6700
|
} finally {
|
|
6605
6701
|
if (targetReserved) workspaceSyncPriorityProcessTargets.delete(message.runId);
|
|
6702
|
+
await releaseWorkerJobResources(resources);
|
|
6703
|
+
cancelledProcessRuns.delete(message.runId);
|
|
6606
6704
|
}
|
|
6607
6705
|
})();
|
|
6608
6706
|
void execution.catch((error) => {
|
package/dist/cjs/package.json
CHANGED