@mastra/docker 0.9.0 → 0.9.1-alpha.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.cjs +129 -38
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +129 -38
- package/dist/index.js.map +1 -1
- package/dist/sandbox/process-manager.d.ts.map +1 -1
- package/package.json +6 -6
package/dist/index.js
CHANGED
|
@@ -141,6 +141,61 @@ case "$err" in
|
|
|
141
141
|
esac
|
|
142
142
|
`;
|
|
143
143
|
/**
|
|
144
|
+
* Upper bound on how long an early stream 'end' waits for an in-flight kill
|
|
145
|
+
* confirmation before settling without termination metadata. The kill helper's
|
|
146
|
+
* own work is bounded (the KILL_SCRIPT polls for at most ~4s), so this only
|
|
147
|
+
* absorbs daemon round-trips; it exists so a wedged `inspect()` cannot leave
|
|
148
|
+
* wait() pending forever.
|
|
149
|
+
*/
|
|
150
|
+
const TERMINATION_CONFIRMATION_DEADLINE_MS = 1e4;
|
|
151
|
+
/**
|
|
152
|
+
* Resolves when `termination` settles, or after
|
|
153
|
+
* TERMINATION_CONFIRMATION_DEADLINE_MS — whichever comes first. Never rejects.
|
|
154
|
+
*/
|
|
155
|
+
function waitForTermination(termination) {
|
|
156
|
+
return new Promise((resolve) => {
|
|
157
|
+
const timer = setTimeout(resolve, TERMINATION_CONFIRMATION_DEADLINE_MS);
|
|
158
|
+
const done = () => {
|
|
159
|
+
clearTimeout(timer);
|
|
160
|
+
resolve();
|
|
161
|
+
};
|
|
162
|
+
termination.then(done, done);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Resolves with `work`'s value, or `fallback` if it has not settled within `ms`.
|
|
167
|
+
* Never rejects. Bounds a single daemon round-trip, so one call that never
|
|
168
|
+
* answers cannot leave wait() pending past its deadline.
|
|
169
|
+
*/
|
|
170
|
+
function withDeadline(work, ms, fallback) {
|
|
171
|
+
return new Promise((resolve) => {
|
|
172
|
+
const timer = setTimeout(() => resolve(fallback), Math.max(0, ms));
|
|
173
|
+
const done = (value) => {
|
|
174
|
+
clearTimeout(timer);
|
|
175
|
+
resolve(value);
|
|
176
|
+
};
|
|
177
|
+
work.then(done, () => done(fallback));
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Polls `exec.inspect()` until the exec reports it is no longer running, bounded
|
|
182
|
+
* by `deadline` (an absolute `Date.now()` timestamp). A stream can close without
|
|
183
|
+
* 'end' while the process is still alive, and settling from inspect then would
|
|
184
|
+
* publish an exit for a process that never exited — but waiting unbounded could
|
|
185
|
+
* leave wait() pending forever, so each call is bounded too. Returns the last
|
|
186
|
+
* inspect result, which may still report Running: true if the bound was reached,
|
|
187
|
+
* or undefined if no call settled in time.
|
|
188
|
+
*/
|
|
189
|
+
async function waitForExecToStop(exec, deadline) {
|
|
190
|
+
let info;
|
|
191
|
+
while (Date.now() < deadline) {
|
|
192
|
+
info = await withDeadline(exec.inspect(), deadline - Date.now(), void 0);
|
|
193
|
+
if (!info || !info.Running) return info;
|
|
194
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
195
|
+
}
|
|
196
|
+
return info;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
144
199
|
* Wraps a Docker exec instance to conform to Mastra's ProcessHandle.
|
|
145
200
|
* Not exported — internal to this module.
|
|
146
201
|
*
|
|
@@ -157,6 +212,12 @@ var DockerProcessHandle = class extends ProcessHandle {
|
|
|
157
212
|
_killed = false;
|
|
158
213
|
/** @internal Set by the timeout path to distinguish timeout kills from explicit kills */
|
|
159
214
|
_timedOut = false;
|
|
215
|
+
/**
|
|
216
|
+
* @internal In-flight kill confirmation, set while kill() is verifying the
|
|
217
|
+
* process group is gone. An early stream 'end' awaits it (bounded) so
|
|
218
|
+
* termination metadata is not dropped when the target's stream closes first.
|
|
219
|
+
*/
|
|
220
|
+
_terminationPromise = null;
|
|
160
221
|
_waitPromise = null;
|
|
161
222
|
_stdinStream = null;
|
|
162
223
|
_execStream = null;
|
|
@@ -199,6 +260,20 @@ var DockerProcessHandle = class extends ProcessHandle {
|
|
|
199
260
|
}
|
|
200
261
|
async kill() {
|
|
201
262
|
if (this._exitCode !== void 0) return false;
|
|
263
|
+
if (this._terminationPromise) return this._terminationPromise;
|
|
264
|
+
const termination = this._runKillHelper();
|
|
265
|
+
this._terminationPromise = termination;
|
|
266
|
+
try {
|
|
267
|
+
return await termination;
|
|
268
|
+
} finally {
|
|
269
|
+
if (this._terminationPromise === termination) this._terminationPromise = null;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Runs the kill helper and verifies the process group is gone before reporting
|
|
274
|
+
* success, so a `true` result means the targets have actually stopped.
|
|
275
|
+
*/
|
|
276
|
+
async _runKillHelper() {
|
|
202
277
|
try {
|
|
203
278
|
const killExec = await this._container.exec({
|
|
204
279
|
Cmd: [
|
|
@@ -325,52 +400,68 @@ var DockerProcessManager = class extends SandboxProcessManager {
|
|
|
325
400
|
}
|
|
326
401
|
if (combined.length > 0 && buffer.length === 0) buffer.push(combined);
|
|
327
402
|
});
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
success: exitCode === 0,
|
|
334
|
-
exitCode,
|
|
335
|
-
stdout: handle.stdout,
|
|
336
|
-
stderr: handle.stderr,
|
|
337
|
-
executionTimeMs: Date.now() - startTime
|
|
338
|
-
});
|
|
339
|
-
} catch {
|
|
340
|
-
handle._setExitCode(1);
|
|
341
|
-
resolve({
|
|
342
|
-
success: false,
|
|
343
|
-
exitCode: 1,
|
|
344
|
-
stdout: handle.stdout,
|
|
345
|
-
stderr: handle.stderr,
|
|
346
|
-
executionTimeMs: Date.now() - startTime
|
|
347
|
-
});
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
stream.on("close", () => {
|
|
351
|
-
if (handle.exitCode !== void 0) return;
|
|
352
|
-
if (!handle._killed) return;
|
|
353
|
-
handle._setExitCode(137);
|
|
403
|
+
let settled = false;
|
|
404
|
+
const settle = (exitCode, metadata = {}) => {
|
|
405
|
+
if (settled) return;
|
|
406
|
+
settled = true;
|
|
407
|
+
handle._setExitCode(exitCode);
|
|
354
408
|
resolve({
|
|
355
|
-
success:
|
|
356
|
-
exitCode
|
|
409
|
+
success: exitCode === 0,
|
|
410
|
+
exitCode,
|
|
357
411
|
stdout: handle.stdout,
|
|
358
412
|
stderr: handle.stderr,
|
|
359
413
|
executionTimeMs: Date.now() - startTime,
|
|
414
|
+
...metadata
|
|
415
|
+
});
|
|
416
|
+
};
|
|
417
|
+
const settleTerminated = () => {
|
|
418
|
+
settle(137, {
|
|
360
419
|
killed: true,
|
|
361
420
|
timedOut: handle._timedOut
|
|
362
421
|
});
|
|
422
|
+
};
|
|
423
|
+
stream.on("end", async () => {
|
|
424
|
+
if (handle._terminationPromise) await waitForTermination(handle._terminationPromise);
|
|
425
|
+
if (settled) return;
|
|
426
|
+
if (handle._killed) {
|
|
427
|
+
settleTerminated();
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
try {
|
|
431
|
+
const info = await exec.inspect();
|
|
432
|
+
settle(info.ExitCode ?? 1);
|
|
433
|
+
} catch {
|
|
434
|
+
settle(1);
|
|
435
|
+
}
|
|
363
436
|
});
|
|
364
|
-
stream.on("
|
|
365
|
-
|
|
366
|
-
handle.
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
437
|
+
stream.on("close", async () => {
|
|
438
|
+
const deadline = Date.now() + TERMINATION_CONFIRMATION_DEADLINE_MS;
|
|
439
|
+
if (handle._terminationPromise) await waitForTermination(handle._terminationPromise);
|
|
440
|
+
if (settled) return;
|
|
441
|
+
if (handle._killed) {
|
|
442
|
+
settleTerminated();
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
try {
|
|
446
|
+
const info = await waitForExecToStop(exec, deadline);
|
|
447
|
+
if (settled) return;
|
|
448
|
+
if (handle._killed) {
|
|
449
|
+
settleTerminated();
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
settle(info?.ExitCode ?? 1);
|
|
453
|
+
} catch {
|
|
454
|
+
settle(1);
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
stream.on("error", async () => {
|
|
458
|
+
if (handle._terminationPromise) await waitForTermination(handle._terminationPromise);
|
|
459
|
+
if (settled) return;
|
|
460
|
+
if (handle._killed) {
|
|
461
|
+
settleTerminated();
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
settle(1, { stderr: handle.stderr || "Stream error" });
|
|
374
465
|
});
|
|
375
466
|
});
|
|
376
467
|
const resolvedTimeout = options.timeout ?? this._defaultTimeout;
|