@mcmcjs/julia 0.6.1 → 0.7.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/fitlib.jl +94 -6
- package/dist/index.cjs +190 -56
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -7
- package/dist/index.d.ts +21 -7
- package/dist/index.js +169 -36
- package/dist/index.js.map +1 -1
- package/dist/julia-env/Manifest.toml +1895 -0
- package/dist/julia-env/Project.toml +10 -0
- package/dist/worker.jl +8 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -53,7 +53,7 @@ var juliaEngine = {
|
|
|
53
53
|
};
|
|
54
54
|
|
|
55
55
|
// src/fit.ts
|
|
56
|
-
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
56
|
+
import { existsSync as existsSync2, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
57
57
|
import { join as join3 } from "path";
|
|
58
58
|
import {
|
|
59
59
|
canonicalJson,
|
|
@@ -63,6 +63,7 @@ import {
|
|
|
63
63
|
|
|
64
64
|
// src/runner-common.ts
|
|
65
65
|
import { createHash } from "crypto";
|
|
66
|
+
import { existsSync } from "fs";
|
|
66
67
|
import { tmpdir } from "os";
|
|
67
68
|
import { dirname, join as join2 } from "path";
|
|
68
69
|
import { fileURLToPath } from "url";
|
|
@@ -70,11 +71,19 @@ function sharedTmpParent() {
|
|
|
70
71
|
const uid = typeof process.getuid === "function" ? `-${process.getuid()}` : "";
|
|
71
72
|
return join2(tmpdir(), `mcmcjs${uid}`);
|
|
72
73
|
}
|
|
74
|
+
function driverFile(name) {
|
|
75
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
76
|
+
const beside = join2(here, name);
|
|
77
|
+
return existsSync(beside) ? beside : join2(here, "driver", name);
|
|
78
|
+
}
|
|
73
79
|
function driverPath() {
|
|
74
|
-
return
|
|
80
|
+
return driverFile("driver.jl");
|
|
75
81
|
}
|
|
76
82
|
function workerPath() {
|
|
77
|
-
return
|
|
83
|
+
return driverFile("worker.jl");
|
|
84
|
+
}
|
|
85
|
+
function pinnedEnvDir() {
|
|
86
|
+
return join2(dirname(fileURLToPath(import.meta.url)), "julia-env");
|
|
78
87
|
}
|
|
79
88
|
function sha256(text) {
|
|
80
89
|
return createHash("sha256").update(text).digest("hex");
|
|
@@ -110,7 +119,7 @@ function makeRequestDir(kind) {
|
|
|
110
119
|
mkdirSync(parent, { recursive: true });
|
|
111
120
|
return mkdtempSync(join3(parent, `${kind}-`));
|
|
112
121
|
}
|
|
113
|
-
function fitRequest(spec, outPath) {
|
|
122
|
+
function fitRequest(spec, outPath, opts) {
|
|
114
123
|
return {
|
|
115
124
|
schema_version: spec.schema_version,
|
|
116
125
|
backend: { id: spec.backend.id },
|
|
@@ -118,12 +127,13 @@ function fitRequest(spec, outPath) {
|
|
|
118
127
|
data: spec.data,
|
|
119
128
|
sampler: spec.sampler,
|
|
120
129
|
seed: spec.seed,
|
|
121
|
-
out: outPath
|
|
130
|
+
out: outPath,
|
|
131
|
+
...opts?.streamDraws ? { stream_draws: true } : {}
|
|
122
132
|
};
|
|
123
133
|
}
|
|
124
134
|
function finalizeOkFit(spec, resolved, io, provenance, startedAt, elapsedMs) {
|
|
125
135
|
const runtimeRequested = spec.backend.version;
|
|
126
|
-
if (!
|
|
136
|
+
if (!existsSync2(io.outPath)) {
|
|
127
137
|
return {
|
|
128
138
|
status: "error",
|
|
129
139
|
runtimeRequested,
|
|
@@ -152,7 +162,7 @@ function finalizeOkFit(spec, resolved, io, provenance, startedAt, elapsedMs) {
|
|
|
152
162
|
runtime: { requested: runtimeRequested, actual: julia, path: resolved.command },
|
|
153
163
|
manifest_sha256: provenance?.manifest_sha256,
|
|
154
164
|
packages: provenance?.packages,
|
|
155
|
-
model_sha256:
|
|
165
|
+
model_sha256: existsSync2(spec.modelPath) ? sha256(readFileSync(spec.modelPath, "utf8")) : void 0,
|
|
156
166
|
data_sha256: io.dataSha256 ?? sha256(canonicalJson(spec.data)),
|
|
157
167
|
...io.dataFile ? { data_file: io.dataFile } : {},
|
|
158
168
|
samples_file: io.outPath,
|
|
@@ -173,10 +183,16 @@ async function runFit(spec, resolved, io) {
|
|
|
173
183
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
174
184
|
const start = performance.now();
|
|
175
185
|
const runtimeRequested = spec.backend.version;
|
|
186
|
+
if (io.signal?.aborted) {
|
|
187
|
+
return { status: "cancelled", runtimeRequested, elapsedMs: 0 };
|
|
188
|
+
}
|
|
176
189
|
const ownTmp = io.tmpDir === void 0;
|
|
177
190
|
const tmp = io.tmpDir ?? makeRequestDir("fit");
|
|
178
191
|
const requestPath = join3(tmp, "request.json");
|
|
179
|
-
writeFileSync(
|
|
192
|
+
writeFileSync(
|
|
193
|
+
requestPath,
|
|
194
|
+
JSON.stringify(fitRequest(spec, io.outPath, { streamDraws: io.onDraws !== void 0 }))
|
|
195
|
+
);
|
|
180
196
|
const args = [
|
|
181
197
|
...resolved.args,
|
|
182
198
|
"--startup-file=no",
|
|
@@ -187,15 +203,21 @@ async function runFit(spec, resolved, io) {
|
|
|
187
203
|
let stdout;
|
|
188
204
|
let stderr;
|
|
189
205
|
let code;
|
|
206
|
+
let cancelled;
|
|
190
207
|
try {
|
|
191
|
-
({ stdout, stderr, code } = await io.spawn(resolved.command, args, {
|
|
192
|
-
onProgress: io.onProgress
|
|
208
|
+
({ stdout, stderr, code, cancelled } = await io.spawn(resolved.command, args, {
|
|
209
|
+
onProgress: io.onProgress,
|
|
210
|
+
onDraws: io.onDraws,
|
|
211
|
+
signal: io.signal
|
|
193
212
|
}));
|
|
194
213
|
} finally {
|
|
195
214
|
if (ownTmp) rmSync(tmp, { recursive: true, force: true });
|
|
196
215
|
}
|
|
197
216
|
const elapsedMs = Math.round(performance.now() - start);
|
|
198
|
-
if (
|
|
217
|
+
if (cancelled) {
|
|
218
|
+
return { status: "cancelled", runtimeRequested, elapsedMs };
|
|
219
|
+
}
|
|
220
|
+
if (code !== 0 || !existsSync2(io.outPath)) {
|
|
199
221
|
const failure = lastJsonLine(stderr);
|
|
200
222
|
const stage = toStage(failure?.stage);
|
|
201
223
|
const error = failure?.error ?? stderr.trim().split("\n").pop() ?? `julia exited with code ${code}`;
|
|
@@ -205,7 +227,7 @@ async function runFit(spec, resolved, io) {
|
|
|
205
227
|
}
|
|
206
228
|
|
|
207
229
|
// src/predict.ts
|
|
208
|
-
import { existsSync as
|
|
230
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
209
231
|
import { join as join4 } from "path";
|
|
210
232
|
import {
|
|
211
233
|
canonicalJson as canonicalJson2,
|
|
@@ -260,7 +282,7 @@ async function runPredict(spec, resolved, io) {
|
|
|
260
282
|
if (ownTmp) rmSync2(tmp, { recursive: true, force: true });
|
|
261
283
|
}
|
|
262
284
|
const elapsedMs = Math.round(performance.now() - start);
|
|
263
|
-
if (code !== 0 || !
|
|
285
|
+
if (code !== 0 || !existsSync3(io.outPath)) {
|
|
264
286
|
const failure = lastJsonLine(stderr);
|
|
265
287
|
const error = failure?.error ?? stderr.trim().split("\n").pop() ?? `julia exited with code ${code}`;
|
|
266
288
|
return { status: "error", runtimeRequested, elapsedMs, stage: toStage(failure?.stage), error };
|
|
@@ -286,10 +308,10 @@ async function runPredict(spec, resolved, io) {
|
|
|
286
308
|
runtime: { requested: runtimeRequested, actual: julia, path: resolved.command },
|
|
287
309
|
manifest_sha256: provenance?.manifest_sha256,
|
|
288
310
|
packages: provenance?.packages,
|
|
289
|
-
model_sha256:
|
|
311
|
+
model_sha256: existsSync3(spec.modelPath) ? sha256(readFileSync2(spec.modelPath, "utf8")) : void 0,
|
|
290
312
|
data_sha256: sha256(canonicalJson2(data)),
|
|
291
313
|
posterior_samples: io.samplesPath,
|
|
292
|
-
posterior_samples_sha256:
|
|
314
|
+
posterior_samples_sha256: existsSync3(io.samplesPath) ? sha256(readFileSync2(io.samplesPath, "utf8")) : void 0,
|
|
293
315
|
samples_file: io.outPath,
|
|
294
316
|
started_at: startedAt,
|
|
295
317
|
elapsed_ms: elapsedMs
|
|
@@ -306,10 +328,10 @@ async function runPredict(spec, resolved, io) {
|
|
|
306
328
|
}
|
|
307
329
|
|
|
308
330
|
// src/project.ts
|
|
309
|
-
import { existsSync as
|
|
331
|
+
import { copyFileSync, existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
310
332
|
import { homedir as homedir2 } from "os";
|
|
311
333
|
import { join as join5 } from "path";
|
|
312
|
-
import { canonicalJson as canonicalJson3 } from "@mcmcjs/core";
|
|
334
|
+
import { canonicalJson as canonicalJson3, DEFAULT_JULIA_CHANNEL } from "@mcmcjs/core";
|
|
313
335
|
import { createRunner as createRunner3 } from "@mcmcjs/engine";
|
|
314
336
|
var PACKAGES = [
|
|
315
337
|
"Turing",
|
|
@@ -354,8 +376,13 @@ function managedProjectDir(version, pins) {
|
|
|
354
376
|
function sentinelPath(dir) {
|
|
355
377
|
return join5(dir, ".mcmcjs-packages.json");
|
|
356
378
|
}
|
|
379
|
+
var PROVISION_GENERATION = 1;
|
|
357
380
|
function expectedSentinel(pins) {
|
|
358
|
-
return canonicalJson3({
|
|
381
|
+
return canonicalJson3({
|
|
382
|
+
gen: PROVISION_GENERATION,
|
|
383
|
+
packages: [...PACKAGES].sort(),
|
|
384
|
+
pins: pins ?? {}
|
|
385
|
+
});
|
|
359
386
|
}
|
|
360
387
|
function provisioned(dir, pins) {
|
|
361
388
|
try {
|
|
@@ -365,7 +392,7 @@ function provisioned(dir, pins) {
|
|
|
365
392
|
}
|
|
366
393
|
}
|
|
367
394
|
function managedProjectReady(dir = managedProjectDir(), pins) {
|
|
368
|
-
return
|
|
395
|
+
return existsSync4(join5(dir, "Project.toml")) && provisioned(dir, pins);
|
|
369
396
|
}
|
|
370
397
|
function packageSpecsCode(pins) {
|
|
371
398
|
const specs = PACKAGES.map((name) => {
|
|
@@ -374,12 +401,26 @@ function packageSpecsCode(pins) {
|
|
|
374
401
|
});
|
|
375
402
|
return `[${specs.join(", ")}]`;
|
|
376
403
|
}
|
|
377
|
-
|
|
404
|
+
function usesPinnedEnv(version, pins) {
|
|
405
|
+
return !hasPins(pins) && version === DEFAULT_JULIA_CHANNEL && existsSync4(pinnedEnvDir());
|
|
406
|
+
}
|
|
407
|
+
async function ensureProject(juliaBin, run = createRunner3(30 * 6e4), dir = managedProjectDir(), pins, opts) {
|
|
378
408
|
validatePins(pins);
|
|
379
409
|
if (managedProjectReady(dir, pins)) return dir;
|
|
380
410
|
mkdirSync2(dir, { recursive: true });
|
|
381
|
-
|
|
382
|
-
|
|
411
|
+
if (usesPinnedEnv(opts?.version, pins)) {
|
|
412
|
+
copyFileSync(join5(pinnedEnvDir(), "Project.toml"), join5(dir, "Project.toml"));
|
|
413
|
+
copyFileSync(join5(pinnedEnvDir(), "Manifest.toml"), join5(dir, "Manifest.toml"));
|
|
414
|
+
await run(juliaBin, [
|
|
415
|
+
"--startup-file=no",
|
|
416
|
+
`--project=${dir}`,
|
|
417
|
+
"-e",
|
|
418
|
+
"using Pkg; Pkg.instantiate(); Pkg.precompile()"
|
|
419
|
+
]);
|
|
420
|
+
} else {
|
|
421
|
+
const code = `using Pkg; Pkg.add(${packageSpecsCode(pins)}); Pkg.precompile()`;
|
|
422
|
+
await run(juliaBin, ["--startup-file=no", `--project=${dir}`, "-e", code]);
|
|
423
|
+
}
|
|
383
424
|
writeFileSync3(sentinelPath(dir), expectedSentinel(pins));
|
|
384
425
|
return dir;
|
|
385
426
|
}
|
|
@@ -414,6 +455,7 @@ async function runMatrix(spec, versions, io) {
|
|
|
414
455
|
entry = { version, status: "error", elapsedMs: 0, error: error.message };
|
|
415
456
|
}
|
|
416
457
|
entries.push(entry);
|
|
458
|
+
if (entry.status === "cancelled") break;
|
|
417
459
|
if (entry.status === "error" && !io.keepGoing) break;
|
|
418
460
|
}
|
|
419
461
|
return {
|
|
@@ -423,28 +465,38 @@ async function runMatrix(spec, versions, io) {
|
|
|
423
465
|
}
|
|
424
466
|
|
|
425
467
|
// src/setup.ts
|
|
468
|
+
import { DEFAULT_JULIA_CHANNEL as DEFAULT_JULIA_CHANNEL2 } from "@mcmcjs/core";
|
|
426
469
|
var JULIAUP_INSTALL_URL = "https://install.julialang.org";
|
|
427
470
|
function juliaupInstallCommand(platform) {
|
|
428
471
|
if (platform === "win32") {
|
|
429
472
|
return null;
|
|
430
473
|
}
|
|
431
|
-
return {
|
|
474
|
+
return {
|
|
475
|
+
command: "sh",
|
|
476
|
+
args: [
|
|
477
|
+
"-c",
|
|
478
|
+
`curl -fsSL ${JULIAUP_INSTALL_URL} | sh -s -- --yes --default-channel ${DEFAULT_JULIA_CHANNEL2}`
|
|
479
|
+
]
|
|
480
|
+
};
|
|
432
481
|
}
|
|
433
482
|
function planSetup(report, platform) {
|
|
434
|
-
if (report.julia.found) return [];
|
|
483
|
+
if (report.julia.found && report.julia.version === DEFAULT_JULIA_CHANNEL2) return [];
|
|
435
484
|
if (report.juliaup.found) {
|
|
436
485
|
return [
|
|
437
486
|
{
|
|
438
487
|
tool: "julia",
|
|
439
|
-
label:
|
|
440
|
-
command: {
|
|
488
|
+
label: `install the pinned Julia ${DEFAULT_JULIA_CHANNEL2} via juliaup`,
|
|
489
|
+
command: {
|
|
490
|
+
command: report.juliaup.path ?? "juliaup",
|
|
491
|
+
args: ["add", DEFAULT_JULIA_CHANNEL2]
|
|
492
|
+
}
|
|
441
493
|
}
|
|
442
494
|
];
|
|
443
495
|
}
|
|
444
496
|
return [
|
|
445
497
|
{
|
|
446
498
|
tool: "juliaup",
|
|
447
|
-
label:
|
|
499
|
+
label: `install juliaup with the pinned Julia ${DEFAULT_JULIA_CHANNEL2}`,
|
|
448
500
|
command: juliaupInstallCommand(platform)
|
|
449
501
|
}
|
|
450
502
|
];
|
|
@@ -457,8 +509,8 @@ async function runSetup(options = {}) {
|
|
|
457
509
|
dryRun = false
|
|
458
510
|
} = options;
|
|
459
511
|
const before = await runDoctor(runner);
|
|
460
|
-
if (before.ready) return { ...before, steps: [] };
|
|
461
512
|
const plan = planSetup(before, platform);
|
|
513
|
+
if (plan.length === 0) return { ...before, steps: [] };
|
|
462
514
|
if (dryRun) {
|
|
463
515
|
return {
|
|
464
516
|
...before,
|
|
@@ -563,10 +615,10 @@ function assertVersionsInstalled(channels, installed) {
|
|
|
563
615
|
|
|
564
616
|
// src/worker.ts
|
|
565
617
|
import { spawn } from "child_process";
|
|
566
|
-
import { mkdirSync as mkdirSync3, readdirSync, rmdirSync, rmSync as rmSync3, statSync } from "fs";
|
|
618
|
+
import { mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync4, rmdirSync, rmSync as rmSync3, statSync } from "fs";
|
|
567
619
|
import { createConnection } from "net";
|
|
568
620
|
import { join as join7 } from "path";
|
|
569
|
-
import { parseProgressLine } from "@mcmcjs/engine";
|
|
621
|
+
import { parseDrawBatchLine, parseProgressLine } from "@mcmcjs/engine";
|
|
570
622
|
var START_WAIT_MS = 18e4;
|
|
571
623
|
var CONNECT_TIMEOUT_MS = 1e3;
|
|
572
624
|
var STOP_ACK_TIMEOUT_MS = 3e3;
|
|
@@ -576,6 +628,27 @@ function fitInactivityTimeoutMs() {
|
|
|
576
628
|
}
|
|
577
629
|
var WorkerTimeoutError = class extends Error {
|
|
578
630
|
};
|
|
631
|
+
var FitCancelledError = class extends Error {
|
|
632
|
+
};
|
|
633
|
+
function workerPidPath(socket) {
|
|
634
|
+
return `${socket}.pid`;
|
|
635
|
+
}
|
|
636
|
+
function killWorker(socket) {
|
|
637
|
+
const pidPath = workerPidPath(socket);
|
|
638
|
+
try {
|
|
639
|
+
const pid = Number(readFileSync4(pidPath, "utf8").trim());
|
|
640
|
+
if (Number.isInteger(pid) && pid > 0) {
|
|
641
|
+
try {
|
|
642
|
+
process.kill(-pid, "SIGKILL");
|
|
643
|
+
} catch {
|
|
644
|
+
process.kill(pid, "SIGKILL");
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
} catch {
|
|
648
|
+
}
|
|
649
|
+
rmSync3(socket, { force: true });
|
|
650
|
+
rmSync3(pidPath, { force: true });
|
|
651
|
+
}
|
|
579
652
|
function workersDir() {
|
|
580
653
|
const runtime = process.env.XDG_RUNTIME_DIR;
|
|
581
654
|
const dir = runtime ? join7(runtime, "mcmcjs") : join7(sharedTmpParent(), "workers");
|
|
@@ -627,12 +700,13 @@ function releaseStartLock(socketPath) {
|
|
|
627
700
|
} catch {
|
|
628
701
|
}
|
|
629
702
|
}
|
|
630
|
-
async function ensureWorker(resolved, projectDir, notify) {
|
|
703
|
+
async function ensureWorker(resolved, projectDir, notify, signal) {
|
|
631
704
|
const path = workerSocketPath(resolved.command, projectDir);
|
|
632
705
|
try {
|
|
633
706
|
return await connectOnce(path);
|
|
634
707
|
} catch {
|
|
635
708
|
}
|
|
709
|
+
if (signal?.aborted) throw new FitCancelledError();
|
|
636
710
|
let spawnFailure;
|
|
637
711
|
const startedHere = acquireStartLock(path);
|
|
638
712
|
if (startedHere) {
|
|
@@ -661,6 +735,7 @@ async function ensureWorker(resolved, projectDir, notify) {
|
|
|
661
735
|
try {
|
|
662
736
|
const deadline = Date.now() + START_WAIT_MS;
|
|
663
737
|
for (; ; ) {
|
|
738
|
+
if (signal?.aborted) throw new FitCancelledError();
|
|
664
739
|
if (spawnFailure) throw spawnFailure;
|
|
665
740
|
try {
|
|
666
741
|
return await connectOnce(path);
|
|
@@ -673,16 +748,27 @@ async function ensureWorker(resolved, projectDir, notify) {
|
|
|
673
748
|
if (startedHere) releaseStartLock(path);
|
|
674
749
|
}
|
|
675
750
|
}
|
|
676
|
-
function readWorkerResponse(sock, onProgress, inactivityMs = fitInactivityTimeoutMs()) {
|
|
751
|
+
function readWorkerResponse(sock, onProgress, onDraws, signal, inactivityMs = fitInactivityTimeoutMs()) {
|
|
677
752
|
return new Promise((resolve, reject) => {
|
|
678
753
|
let pending = "";
|
|
679
754
|
let settled = false;
|
|
755
|
+
const onAbort = () => {
|
|
756
|
+
settle(() => {
|
|
757
|
+
sock.destroy();
|
|
758
|
+
reject(new FitCancelledError());
|
|
759
|
+
});
|
|
760
|
+
};
|
|
680
761
|
const settle = (fn) => {
|
|
681
762
|
if (settled) return;
|
|
682
763
|
settled = true;
|
|
683
764
|
sock.setTimeout(0);
|
|
765
|
+
signal?.removeEventListener("abort", onAbort);
|
|
684
766
|
fn();
|
|
685
767
|
};
|
|
768
|
+
if (signal) {
|
|
769
|
+
if (signal.aborted) onAbort();
|
|
770
|
+
else signal.addEventListener("abort", onAbort, { once: true });
|
|
771
|
+
}
|
|
686
772
|
sock.setTimeout(inactivityMs, () => {
|
|
687
773
|
const error = new WorkerTimeoutError(
|
|
688
774
|
`the worker sent nothing for ${Math.round(inactivityMs / 6e4)} minutes`
|
|
@@ -705,6 +791,11 @@ function readWorkerResponse(sock, onProgress, inactivityMs = fitInactivityTimeou
|
|
|
705
791
|
onProgress?.(progress);
|
|
706
792
|
continue;
|
|
707
793
|
}
|
|
794
|
+
const batch = parseDrawBatchLine(line);
|
|
795
|
+
if (batch) {
|
|
796
|
+
onDraws?.(batch);
|
|
797
|
+
continue;
|
|
798
|
+
}
|
|
708
799
|
try {
|
|
709
800
|
const doc = JSON.parse(line);
|
|
710
801
|
settle(() => {
|
|
@@ -723,10 +814,48 @@ function readWorkerResponse(sock, onProgress, inactivityMs = fitInactivityTimeou
|
|
|
723
814
|
async function runFitViaWorker(spec, resolved, io) {
|
|
724
815
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
725
816
|
const start = performance.now();
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
817
|
+
if (io.signal?.aborted) {
|
|
818
|
+
return { status: "cancelled", runtimeRequested: spec.backend.version, elapsedMs: 0 };
|
|
819
|
+
}
|
|
820
|
+
let sock;
|
|
821
|
+
try {
|
|
822
|
+
sock = await ensureWorker(resolved, io.projectDir, io.notify, io.signal);
|
|
823
|
+
} catch (error) {
|
|
824
|
+
if (error instanceof FitCancelledError) {
|
|
825
|
+
return {
|
|
826
|
+
status: "cancelled",
|
|
827
|
+
runtimeRequested: spec.backend.version,
|
|
828
|
+
elapsedMs: Math.round(performance.now() - start)
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
throw error;
|
|
832
|
+
}
|
|
833
|
+
if (io.signal?.aborted) {
|
|
834
|
+
sock.destroy();
|
|
835
|
+
return {
|
|
836
|
+
status: "cancelled",
|
|
837
|
+
runtimeRequested: spec.backend.version,
|
|
838
|
+
elapsedMs: Math.round(performance.now() - start)
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
sock.write(
|
|
842
|
+
`${JSON.stringify(fitRequest(spec, io.outPath, { streamDraws: io.onDraws !== void 0 }))}
|
|
843
|
+
`
|
|
844
|
+
);
|
|
845
|
+
let final;
|
|
846
|
+
try {
|
|
847
|
+
final = await readWorkerResponse(sock, io.onProgress, io.onDraws, io.signal);
|
|
848
|
+
} catch (error) {
|
|
849
|
+
if (error instanceof FitCancelledError) {
|
|
850
|
+
killWorker(workerSocketPath(resolved.command, io.projectDir));
|
|
851
|
+
return {
|
|
852
|
+
status: "cancelled",
|
|
853
|
+
runtimeRequested: spec.backend.version,
|
|
854
|
+
elapsedMs: Math.round(performance.now() - start)
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
throw error;
|
|
858
|
+
}
|
|
730
859
|
const elapsedMs = Math.round(performance.now() - start);
|
|
731
860
|
if (final.ok !== true) {
|
|
732
861
|
if (final.stage === "worker") throw new Error(String(final.error ?? "worker error"));
|
|
@@ -748,6 +877,9 @@ async function runFitViaWorker(spec, resolved, io) {
|
|
|
748
877
|
);
|
|
749
878
|
}
|
|
750
879
|
async function runFitAuto(spec, resolved, io) {
|
|
880
|
+
if (io.signal?.aborted) {
|
|
881
|
+
return { status: "cancelled", runtimeRequested: spec.backend.version, elapsedMs: 0 };
|
|
882
|
+
}
|
|
751
883
|
if (io.daemon && process.platform !== "win32") {
|
|
752
884
|
const start = performance.now();
|
|
753
885
|
try {
|
|
@@ -819,6 +951,7 @@ export {
|
|
|
819
951
|
gcVersions,
|
|
820
952
|
juliaEngine,
|
|
821
953
|
juliaupInstallCommand,
|
|
954
|
+
killWorker,
|
|
822
955
|
listVersions,
|
|
823
956
|
listWorkers,
|
|
824
957
|
managedProjectDir,
|