@sshkeda/task 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +131 -2
- package/package.json +41 -4
- package/src/index.ts +2 -0
- package/src/lib/errors/index.ts +15 -0
- package/src/lib/errors/internal/errors.ts +147 -0
- package/src/lib/kill-leftover-processes/index.ts +17 -0
- package/src/lib/kill-leftover-processes/internal/command-words.ts +16 -0
- package/src/lib/kill-leftover-processes/internal/find-process-ids.ts +36 -0
- package/src/lib/kill-leftover-processes/internal/kill-process-groups.ts +270 -0
- package/src/lib/kill-leftover-processes/internal/list-linux-processes-from-proc.ts +191 -0
- package/src/lib/kill-leftover-processes/internal/list-macos-processes-with-sysctl.ts +335 -0
- package/src/lib/kill-leftover-processes/internal/list-processes.ts +58 -0
- package/src/lib/kill-leftover-processes/internal/mark-run-processes.ts +367 -0
- package/src/lib/kill-leftover-processes/internal/process-cleanup-errors.ts +17 -0
- package/src/lib/kill-leftover-processes/internal/send-signal.ts +32 -0
- package/src/lib/kill-leftover-processes/internal/signal-run-processes.ts +48 -0
- package/src/lib/kill-leftover-processes/internal/started-process-groups.ts +107 -0
- package/src/lib/main-thread/index.ts +3 -0
- package/src/lib/main-thread/internal/listen-for-stop-requests.ts +102 -0
- package/src/lib/main-thread/internal/run-main-thread.ts +81 -0
- package/src/lib/main-thread/internal/run-root-task-fiber.ts +191 -0
- package/src/lib/main-thread/internal/stops-at-first-failure.ts +20 -0
- package/src/lib/main-thread/internal/trace-the-run.ts +107 -0
- package/src/lib/main-thread/lib/find-code-each-task-depends-on/index.ts +7 -0
- package/src/lib/main-thread/lib/find-code-each-task-depends-on/internal/follow-imports-from-entry-files.ts +306 -0
- package/src/lib/main-thread/lib/find-code-each-task-depends-on/internal/load-all-reporting-first-failure.ts +11 -0
- package/src/lib/main-thread/lib/find-code-each-task-depends-on/internal/make-module-graph.ts +48 -0
- package/src/lib/main-thread/lib/find-code-each-task-depends-on/internal/read-configured-loaders.ts +64 -0
- package/src/lib/main-thread/lib/find-code-each-task-depends-on/internal/resolve-module-specifiers.ts +60 -0
- package/src/lib/main-thread/lib/find-code-each-task-depends-on/internal/rewrite-worker-imports.ts +118 -0
- package/src/lib/main-thread/lib/find-code-each-task-depends-on/internal/worker-import-errors.ts +19 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/index.ts +7 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/internal/handle-worker-events.ts +348 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/internal/make-task-runs.ts +207 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/lib/run-requested-task-once/index.ts +1 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/lib/run-requested-task-once/internal/await-within-counted-limit.ts +29 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/lib/run-requested-task-once/internal/execute-task.ts +272 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/lib/run-requested-task-once/internal/make-task-setup-clock.ts +129 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/lib/run-requested-task-once/internal/run-requested-tasks.ts +135 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/shared/define-task-run-state.ts +288 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/shared/make-stopwatch.ts +39 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/shared/share-standard-input-with-root-task.ts +36 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/shared/stop-task.ts +166 -0
- package/src/lib/main-thread/lib/scan-module-source/index.ts +1 -0
- package/src/lib/main-thread/lib/scan-module-source/internal/find-lexical-bindings.ts +154 -0
- package/src/lib/main-thread/lib/scan-module-source/internal/find-task-declarations.ts +205 -0
- package/src/lib/main-thread/lib/scan-module-source/internal/parse-module-text.ts +34 -0
- package/src/lib/main-thread/lib/scan-module-source/internal/read-literal-string.ts +15 -0
- package/src/lib/main-thread/lib/scan-module-source/internal/read-module-loads.ts +316 -0
- package/src/lib/main-thread/lib/scan-module-source/internal/scan-module-text.ts +70 -0
- package/src/lib/main-thread/lib/scan-module-source/internal/unwrap-type-assertions.ts +10 -0
- package/src/lib/main-thread/lib/scan-module-source/internal/visit-non-reference-identifiers.ts +21 -0
- package/src/lib/main-thread/shared/fail-run.ts +36 -0
- package/src/lib/main-thread/shared/find-failure-reason.ts +43 -0
- package/src/lib/main-thread/shared/find-package-directories.ts +34 -0
- package/src/lib/main-thread/shared/find-tasks-reachable-from-root-task-file.ts +246 -0
- package/src/lib/main-thread/shared/list-directory-paths-up-to-root.ts +13 -0
- package/src/lib/main-thread/shared/main-thread-errors.ts +373 -0
- package/src/lib/main-thread/shared/package-json-errors.ts +93 -0
- package/src/lib/main-thread/shared/provide-discovered-tasks.ts +26 -0
- package/src/lib/main-thread/shared/provide-process-groups.ts +63 -0
- package/src/lib/main-thread/shared/provide-run-root-task-config.ts +66 -0
- package/src/lib/main-thread/shared/provide-stop-state.ts +150 -0
- package/src/lib/main-thread/shared/provide-worker-pool.ts +607 -0
- package/src/lib/main-thread/shared/read-bare-package-name.ts +3 -0
- package/src/lib/main-thread/shared/read-package-json.ts +149 -0
- package/src/lib/main-thread/shared/report-task-failure.ts +31 -0
- package/src/lib/preload-rewritten-imports-into-each-worker/index.ts +5 -0
- package/src/lib/preload-rewritten-imports-into-each-worker/internal/load-rewritten-imports.ts +34 -0
- package/src/lib/supervise-the-run/index.ts +15 -0
- package/src/lib/supervise-the-run/internal/adopt-orphans-on-linux.ts +73 -0
- package/src/lib/supervise-the-run/internal/check-root-task-file.ts +8 -0
- package/src/lib/supervise-the-run/internal/report-ready.ts +12 -0
- package/src/lib/supervise-the-run/internal/share-process-groups.ts +25 -0
- package/src/lib/supervise-the-run/internal/start-watching-the-supervisor.ts +6 -0
- package/src/lib/supervise-the-run/internal/supervise-run.ts +155 -0
- package/src/lib/supervise-the-run/internal/talk-to-the-supervisor.ts +53 -0
- package/src/lib/supervise-the-run/internal/watch-the-supervisor.ts +61 -0
- package/src/lib/task/index.ts +5 -0
- package/src/lib/task/internal/make-tasks.ts +82 -0
- package/src/lib/task/internal/run-command.ts +194 -0
- package/src/lib/task/internal/run-root-task.ts +263 -0
- package/src/lib/task/internal/run-task-lists.ts +51 -0
- package/src/lib/task/internal/trust-output-mode-names.ts +18 -0
- package/src/lib/task/internal/trust-task-results.ts +35 -0
- package/src/lib/task/internal/use-task-services.ts +4 -0
- package/src/lib/worker-thread/index.ts +3 -0
- package/src/lib/worker-thread/internal/answer-main-thread-messages.ts +141 -0
- package/src/lib/worker-thread/internal/describe-task-body-result.ts +91 -0
- package/src/lib/worker-thread/internal/name-config-key-not-set.ts +57 -0
- package/src/lib/worker-thread/internal/run-task-body.ts +117 -0
- package/src/lib/worker-thread/internal/serve-on-the-parent-port.ts +63 -0
- package/src/lib/worker-thread/internal/start-worker-thread.ts +41 -0
- package/src/lib/worker-thread/lib/provide-task-services/index.ts +1 -0
- package/src/lib/worker-thread/lib/provide-task-services/internal/make-task-logger.ts +34 -0
- package/src/lib/worker-thread/lib/provide-task-services/internal/provide-task-services.ts +86 -0
- package/src/lib/worker-thread/lib/provide-task-services/internal/read-standard-input-from-main-thread.ts +58 -0
- package/src/lib/worker-thread/lib/provide-task-services/internal/resolve-paths-from-package-directory.ts +61 -0
- package/src/lib/worker-thread/lib/provide-task-services/internal/run-commands-in-package-directory.ts +24 -0
- package/src/lib/worker-thread/lib/provide-task-services/internal/spawn-commands-with-bun.ts +545 -0
- package/src/lib/worker-thread/lib/provide-task-services/internal/spawn-reported-process.ts +151 -0
- package/src/lib/worker-thread/shared/await-main-thread-answers.ts +76 -0
- package/src/lib/worker-thread/shared/decode-task-result-json.ts +114 -0
- package/src/lib/worker-thread/shared/define-task-body-record.ts +11 -0
- package/src/lib/worker-thread/shared/describe-issue-input.ts +52 -0
- package/src/lib/worker-thread/shared/plain-object.ts +8 -0
- package/src/lib/worker-thread/shared/provide-worker-state.ts +160 -0
- package/src/lib/worker-thread/shared/worker-thread-errors.ts +41 -0
- package/src/shared/attribute-reported-failures.ts +25 -0
- package/src/shared/claim-processes-to-report.ts +22 -0
- package/src/shared/command-errors.ts +44 -0
- package/src/shared/complete-discarded-calls-once-sent.ts +12 -0
- package/src/shared/cut-to-graphemes.ts +12 -0
- package/src/shared/environment-config-errors.ts +74 -0
- package/src/shared/error-fields.ts +13 -0
- package/src/shared/find-bun-loader-for-script.ts +32 -0
- package/src/shared/find-node-modules-package-directory.ts +35 -0
- package/src/shared/find-user-locations-in-stack-traces.ts +64 -0
- package/src/shared/format-error-lines.ts +53 -0
- package/src/shared/format-task-lines.ts +21 -0
- package/src/shared/hold-task-logs.ts +24 -0
- package/src/shared/invariant-errors.ts +28 -0
- package/src/shared/mark-task-worker-thread-contexts.ts +29 -0
- package/src/shared/module-graph-errors.ts +49 -0
- package/src/shared/name-config-key.ts +42 -0
- package/src/shared/names-from-package-json.ts +7 -0
- package/src/shared/print-to-standard-error.ts +48 -0
- package/src/shared/process-errors.ts +191 -0
- package/src/shared/read-environment-config.ts +239 -0
- package/src/shared/record-tasks-made.ts +10 -0
- package/src/shared/report-cause.ts +140 -0
- package/src/shared/report-errors.ts +121 -0
- package/src/shared/resolve-task-options.ts +20 -0
- package/src/shared/rpc.ts +161 -0
- package/src/shared/run-in-child-fiber-and-join.ts +16 -0
- package/src/shared/run-marker.ts +7 -0
- package/src/shared/save-standard-stream-flags.ts +57 -0
- package/src/shared/select-cause-reasons.ts +14 -0
- package/src/shared/signal-run-called-twice.ts +11 -0
- package/src/shared/standard-input-streams.ts +41 -0
- package/src/shared/stop-signals.ts +41 -0
- package/src/shared/task-errors.ts +224 -0
- package/src/shared/task-package.ts +5 -0
- package/src/shared/task-results.ts +55 -0
- package/src/shared/task-services.ts +30 -0
- package/src/shared/write-trace-file.ts +112 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { Effect, FileSystem, Formatter, Option, Predicate, Schema, Struct } from "effect";
|
|
2
|
+
import type { PlatformError } from "effect";
|
|
3
|
+
|
|
4
|
+
import { dieOnInvariantFailure } from "../../../shared/invariant-errors.ts";
|
|
5
|
+
import { describeCauseMessage } from "../../../shared/report-errors.ts";
|
|
6
|
+
import {
|
|
7
|
+
PackageJsonFieldInvalid,
|
|
8
|
+
PackageJsonNameBlank,
|
|
9
|
+
PackageJsonNameInvalid,
|
|
10
|
+
PackageJsonNameNotString,
|
|
11
|
+
PackageJsonNotJson,
|
|
12
|
+
PackageJsonNotObject,
|
|
13
|
+
PackageJsonUnreadable,
|
|
14
|
+
PackageJsonWithoutName,
|
|
15
|
+
} from "./package-json-errors.ts";
|
|
16
|
+
|
|
17
|
+
const DependencyVersions = Schema.Record(Schema.String, Schema.String).annotate({
|
|
18
|
+
expected: "an object of strings",
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const CHECKED_PACKAGE_JSON_FIELDS = Schema.Struct({
|
|
22
|
+
version: Schema.String.annotate({ expected: "a string" }),
|
|
23
|
+
dependencies: DependencyVersions,
|
|
24
|
+
devDependencies: DependencyVersions,
|
|
25
|
+
peerDependencies: DependencyVersions,
|
|
26
|
+
optionalDependencies: DependencyVersions,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const PackageJsonObject = Schema.Record(Schema.String, Schema.Unknown);
|
|
30
|
+
|
|
31
|
+
const PackageJsonFields = CHECKED_PACKAGE_JSON_FIELDS.mapFields(Struct.map(Schema.optional));
|
|
32
|
+
|
|
33
|
+
const NON_BLANK_TEXT = /\S/u;
|
|
34
|
+
|
|
35
|
+
const isPackageName = Schema.is(
|
|
36
|
+
Schema.String.check(Schema.isPattern(/^(?:@[^./][^/]*\/)?[^./][^/]*$/u)),
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
export const readPackageJsonText = (packageJsonFilePath: string) =>
|
|
40
|
+
FileSystem.FileSystem.use((fileSystem) => fileSystem.readFileString(packageJsonFilePath));
|
|
41
|
+
|
|
42
|
+
export const toPackageJsonUnreadable =
|
|
43
|
+
(packageJsonFilePath: string) => (cause: PlatformError.PlatformError) =>
|
|
44
|
+
new PackageJsonUnreadable({ filePath: packageJsonFilePath, cause });
|
|
45
|
+
|
|
46
|
+
export const parsePackageJsonObject = (packageJsonFilePath: string, packageJsonText: string) =>
|
|
47
|
+
Effect.gen(function* () {
|
|
48
|
+
const parsed = yield* Schema.decodeEffect(Schema.fromJsonString(Schema.Unknown))(
|
|
49
|
+
packageJsonText,
|
|
50
|
+
).pipe(
|
|
51
|
+
Effect.catchTag("SchemaError", () =>
|
|
52
|
+
Effect.try({
|
|
53
|
+
try: () => Bun.JSONC.parse(packageJsonText),
|
|
54
|
+
catch: (cause) =>
|
|
55
|
+
new PackageJsonNotJson({
|
|
56
|
+
filePath: packageJsonFilePath,
|
|
57
|
+
parserMessage: describeCauseMessage(cause),
|
|
58
|
+
}),
|
|
59
|
+
}).pipe(
|
|
60
|
+
Effect.andThen(
|
|
61
|
+
Effect.fail(
|
|
62
|
+
new PackageJsonNotJson({ filePath: packageJsonFilePath, parserMessage: null }),
|
|
63
|
+
),
|
|
64
|
+
),
|
|
65
|
+
),
|
|
66
|
+
),
|
|
67
|
+
);
|
|
68
|
+
return yield* Schema.decodeUnknownEffect(PackageJsonObject)(parsed).pipe(
|
|
69
|
+
Effect.mapError(
|
|
70
|
+
() =>
|
|
71
|
+
new PackageJsonNotObject({
|
|
72
|
+
filePath: packageJsonFilePath,
|
|
73
|
+
valueText: Formatter.format(parsed),
|
|
74
|
+
}),
|
|
75
|
+
),
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
export const decodePackageJsonName = (
|
|
80
|
+
packageJsonFilePath: string,
|
|
81
|
+
packageJsonObject: typeof PackageJsonObject.Type,
|
|
82
|
+
) => {
|
|
83
|
+
const { name } = packageJsonObject;
|
|
84
|
+
if (name === undefined) {
|
|
85
|
+
return Effect.succeedNone;
|
|
86
|
+
}
|
|
87
|
+
if (!Predicate.isString(name)) {
|
|
88
|
+
return Effect.fail(
|
|
89
|
+
new PackageJsonNameNotString({
|
|
90
|
+
filePath: packageJsonFilePath,
|
|
91
|
+
nameText: Formatter.format(name),
|
|
92
|
+
}),
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
return NON_BLANK_TEXT.test(name)
|
|
96
|
+
? Effect.succeedSome(name)
|
|
97
|
+
: Effect.fail(new PackageJsonNameBlank({ filePath: packageJsonFilePath, packageName: name }));
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const decodePackageJsonText = (packageJsonFilePath: string) => (packageJsonText: string) =>
|
|
101
|
+
Effect.gen(function* () {
|
|
102
|
+
const packageJsonObject = yield* parsePackageJsonObject(packageJsonFilePath, packageJsonText);
|
|
103
|
+
const name = yield* decodePackageJsonName(packageJsonFilePath, packageJsonObject);
|
|
104
|
+
for (const [fieldName, fieldSchema] of Object.entries(CHECKED_PACKAGE_JSON_FIELDS.fields)) {
|
|
105
|
+
const value = packageJsonObject[fieldName];
|
|
106
|
+
const isInvalidFieldValue = value !== undefined && !Schema.is(fieldSchema)(value);
|
|
107
|
+
if (isInvalidFieldValue) {
|
|
108
|
+
return yield* new PackageJsonFieldInvalid({
|
|
109
|
+
filePath: packageJsonFilePath,
|
|
110
|
+
fieldName,
|
|
111
|
+
valueText: Formatter.format(value),
|
|
112
|
+
expected: yield* Effect.fromNullishOr(
|
|
113
|
+
Schema.resolveAnnotations(fieldSchema)?.expected,
|
|
114
|
+
).pipe(
|
|
115
|
+
dieOnInvariantFailure(
|
|
116
|
+
"package.json decoding",
|
|
117
|
+
"each checked field names what it expects",
|
|
118
|
+
),
|
|
119
|
+
),
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const fields = yield* Schema.decodeEffect(PackageJsonFields)(packageJsonObject).pipe(
|
|
124
|
+
dieOnInvariantFailure("package.json decoding", "fields that passed their checks decode"),
|
|
125
|
+
);
|
|
126
|
+
return { ...fields, name: Option.getOrUndefined(name) };
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
export const readPackageJson = (packageJsonDirectoryPath: string) => {
|
|
130
|
+
const packageJsonFilePath = `${packageJsonDirectoryPath}/package.json`;
|
|
131
|
+
return readPackageJsonText(packageJsonFilePath).pipe(
|
|
132
|
+
Effect.mapError(toPackageJsonUnreadable(packageJsonFilePath)),
|
|
133
|
+
Effect.flatMap(decodePackageJsonText(packageJsonFilePath)),
|
|
134
|
+
Effect.flatMap(({ name, ...packageJson }) =>
|
|
135
|
+
Effect.gen(function* () {
|
|
136
|
+
if (name === undefined) {
|
|
137
|
+
return yield* new PackageJsonWithoutName({ filePath: packageJsonFilePath });
|
|
138
|
+
}
|
|
139
|
+
if (!isPackageName(name)) {
|
|
140
|
+
return yield* new PackageJsonNameInvalid({
|
|
141
|
+
filePath: packageJsonFilePath,
|
|
142
|
+
packageName: name,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return { ...packageJson, name };
|
|
146
|
+
}),
|
|
147
|
+
),
|
|
148
|
+
);
|
|
149
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Cause, Effect, Predicate } from "effect";
|
|
2
|
+
|
|
3
|
+
import { formatCauseLines } from "../../../shared/format-error-lines.ts";
|
|
4
|
+
import { TASK_TRACE_LABEL_PREFIX } from "../../../shared/names-from-package-json.ts";
|
|
5
|
+
import { printTaskLines } from "../../../shared/print-to-standard-error.ts";
|
|
6
|
+
import { reportCause } from "../../../shared/report-cause.ts";
|
|
7
|
+
import { StopState } from "./provide-stop-state.ts";
|
|
8
|
+
|
|
9
|
+
export const reportFailure = (failure: Error) => reportCause(Cause.fail(failure)).failures;
|
|
10
|
+
|
|
11
|
+
export const reportTaskFailure = Effect.fn("reportTaskFailure")(function* (
|
|
12
|
+
taskName: string,
|
|
13
|
+
cause: Parameters<StopState["Service"]["recordTaskFailureCause"]>[1],
|
|
14
|
+
) {
|
|
15
|
+
const shutdown = yield* StopState;
|
|
16
|
+
yield* shutdown.recordTaskFailureCause(taskName, cause);
|
|
17
|
+
const errorLines = formatCauseLines(cause, taskName);
|
|
18
|
+
if (cause.reasons.length > 0) {
|
|
19
|
+
yield* printTaskLines("Error", taskName, errorLines);
|
|
20
|
+
}
|
|
21
|
+
const failures = cause.reasons.filter(Cause.isFailReason).map((reason) => reason.error);
|
|
22
|
+
for (const failure of failures) {
|
|
23
|
+
yield* shutdown.recordPrintedFailure(failure);
|
|
24
|
+
}
|
|
25
|
+
const details = failures
|
|
26
|
+
.map((failure) => (Predicate.hasProperty(failure, "details") ? failure.details : undefined))
|
|
27
|
+
.filter((detail) => Predicate.isString(detail));
|
|
28
|
+
yield* Effect.logInfo(`failed: ${details.length === 0 ? errorLines : details.join("\n")}`).pipe(
|
|
29
|
+
Effect.annotateLogs(`${TASK_TRACE_LABEL_PREFIX}.task`, taskName),
|
|
30
|
+
);
|
|
31
|
+
}, Effect.uninterruptible);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { workerData } from "node:worker_threads";
|
|
2
|
+
|
|
3
|
+
import { Effect, Schema } from "effect";
|
|
4
|
+
|
|
5
|
+
import { RewrittenModuleUnloadable } from "../../../shared/module-graph-errors.ts";
|
|
6
|
+
import { WorkerData } from "../../../shared/rpc.ts";
|
|
7
|
+
|
|
8
|
+
export const loadRewrittenImports = Effect.gen(function* () {
|
|
9
|
+
const rewrittenFiles = new Map(
|
|
10
|
+
Object.entries((yield* Schema.decodeUnknownEffect(WorkerData)(workerData)).rewrittenFiles),
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
Bun.plugin({
|
|
14
|
+
name: "task rewritten imports",
|
|
15
|
+
target: "bun",
|
|
16
|
+
setup: (build) => {
|
|
17
|
+
build.onLoad(
|
|
18
|
+
{
|
|
19
|
+
filter: new RegExp(
|
|
20
|
+
`^(?:${[...rewrittenFiles.keys()].map((path) => RegExp.escape(path)).join("|")})$`,
|
|
21
|
+
"u",
|
|
22
|
+
),
|
|
23
|
+
},
|
|
24
|
+
(loaded) => {
|
|
25
|
+
const rewrittenFile = rewrittenFiles.get(loaded.path);
|
|
26
|
+
if (rewrittenFile === undefined) {
|
|
27
|
+
throw new RewrittenModuleUnloadable({ filePath: loaded.path });
|
|
28
|
+
}
|
|
29
|
+
return rewrittenFile;
|
|
30
|
+
},
|
|
31
|
+
);
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Ref } from "effect";
|
|
2
|
+
|
|
3
|
+
import { supervisorProcessId, supervisorRunMarker } from "./internal/watch-the-supervisor.ts";
|
|
4
|
+
|
|
5
|
+
export { isRootTaskFileThere } from "./internal/check-root-task-file.ts";
|
|
6
|
+
export { reportReady } from "./internal/report-ready.ts";
|
|
7
|
+
export {
|
|
8
|
+
processGroupsSharedWithTheSupervisor,
|
|
9
|
+
shareProcessGroups,
|
|
10
|
+
} from "./internal/share-process-groups.ts";
|
|
11
|
+
export { superviseRun } from "./internal/supervise-run.ts";
|
|
12
|
+
|
|
13
|
+
export const readSupervisorProcessId = Ref.get(supervisorProcessId);
|
|
14
|
+
|
|
15
|
+
export const readSupervisorRunMarker = Ref.get(supervisorRunMarker);
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { dlopen, FFIType } from "bun:ffi";
|
|
2
|
+
|
|
3
|
+
import { Effect, Stream } from "effect";
|
|
4
|
+
|
|
5
|
+
import { listenToSignals } from "../../../shared/stop-signals.ts";
|
|
6
|
+
|
|
7
|
+
const C_LIBRARY_PATH = "libc.so.6";
|
|
8
|
+
const PR_SET_CHILD_SUBREAPER = 36;
|
|
9
|
+
const PRCTL_ENABLE = 1n;
|
|
10
|
+
const PRCTL_UNUSED_ARGUMENT = 0n;
|
|
11
|
+
const P_ALL = 0;
|
|
12
|
+
const WNOHANG = 1;
|
|
13
|
+
const WEXITED = 4;
|
|
14
|
+
const WNOWAIT = 0x01_00_00_00;
|
|
15
|
+
const SIGINFO_BYTES = 128;
|
|
16
|
+
const SIGINFO_PROCESS_ID_OFFSET = 16;
|
|
17
|
+
|
|
18
|
+
const openCLibrary = Effect.acquireRelease(
|
|
19
|
+
Effect.sync(() =>
|
|
20
|
+
dlopen(C_LIBRARY_PATH, {
|
|
21
|
+
prctl: {
|
|
22
|
+
args: [FFIType.i32, FFIType.u64, FFIType.u64, FFIType.u64, FFIType.u64],
|
|
23
|
+
returns: FFIType.i32,
|
|
24
|
+
},
|
|
25
|
+
waitid: { args: [FFIType.i32, FFIType.i32, FFIType.ptr, FFIType.i32], returns: FFIType.i32 },
|
|
26
|
+
waitpid: { args: [FFIType.i32, FFIType.ptr, FFIType.i32], returns: FFIType.i32 },
|
|
27
|
+
}),
|
|
28
|
+
),
|
|
29
|
+
(library) =>
|
|
30
|
+
Effect.sync(() => {
|
|
31
|
+
library.close();
|
|
32
|
+
}),
|
|
33
|
+
).pipe(Effect.map((library) => library.symbols));
|
|
34
|
+
|
|
35
|
+
const reapExitedOrphans = (
|
|
36
|
+
symbols: Effect.Success<typeof openCLibrary>,
|
|
37
|
+
runProcessId: number,
|
|
38
|
+
): void => {
|
|
39
|
+
const information = new Uint8Array(SIGINFO_BYTES);
|
|
40
|
+
const peeked = symbols.waitid(P_ALL, 0, information, WEXITED | WNOHANG | WNOWAIT);
|
|
41
|
+
const processId = new DataView(information.buffer).getInt32(SIGINFO_PROCESS_ID_OFFSET, true);
|
|
42
|
+
const isExitedOrphan = peeked === 0 && processId !== 0 && processId !== runProcessId;
|
|
43
|
+
if (isExitedOrphan) {
|
|
44
|
+
symbols.waitpid(processId, null, 0);
|
|
45
|
+
reapExitedOrphans(symbols, runProcessId);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const adoptOrphans = Effect.gen(function* () {
|
|
50
|
+
if (process.platform !== "linux") {
|
|
51
|
+
return () => Effect.void;
|
|
52
|
+
}
|
|
53
|
+
const symbols = yield* openCLibrary;
|
|
54
|
+
symbols.prctl(
|
|
55
|
+
PR_SET_CHILD_SUBREAPER,
|
|
56
|
+
PRCTL_ENABLE,
|
|
57
|
+
PRCTL_UNUSED_ARGUMENT,
|
|
58
|
+
PRCTL_UNUSED_ARGUMENT,
|
|
59
|
+
PRCTL_UNUSED_ARGUMENT,
|
|
60
|
+
);
|
|
61
|
+
const childSignals = yield* listenToSignals(["SIGCHLD"]);
|
|
62
|
+
return (runProcessId: number) =>
|
|
63
|
+
Stream.fromQueue(childSignals).pipe(
|
|
64
|
+
Stream.runForEach(() =>
|
|
65
|
+
Effect.sync(() => {
|
|
66
|
+
reapExitedOrphans(symbols, runProcessId);
|
|
67
|
+
}),
|
|
68
|
+
),
|
|
69
|
+
Effect.interruptible,
|
|
70
|
+
Effect.forkScoped,
|
|
71
|
+
Effect.asVoid,
|
|
72
|
+
);
|
|
73
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Effect, FileSystem } from "effect";
|
|
2
|
+
|
|
3
|
+
import { RootTaskFileNotChecked } from "../../../shared/task-errors.ts";
|
|
4
|
+
|
|
5
|
+
export const isRootTaskFileThere = FileSystem.FileSystem.pipe(
|
|
6
|
+
Effect.flatMap((fileSystem) => fileSystem.exists(Bun.main)),
|
|
7
|
+
Effect.mapError((cause) => new RootTaskFileNotChecked({ filePath: Bun.main, cause })),
|
|
8
|
+
);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
|
|
3
|
+
import { completeOnceSent } from "../../../shared/complete-discarded-calls-once-sent.ts";
|
|
4
|
+
import { callTheSupervisor } from "./talk-to-the-supervisor.ts";
|
|
5
|
+
|
|
6
|
+
export const reportReady = Effect.scope.pipe(
|
|
7
|
+
Effect.flatMap((scope) =>
|
|
8
|
+
callTheSupervisor((supervisor) =>
|
|
9
|
+
supervisor.ReportReady(undefined, { discard: true }).pipe(completeOnceSent(scope)),
|
|
10
|
+
),
|
|
11
|
+
),
|
|
12
|
+
);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
|
|
3
|
+
import type { startedProcessGroup } from "../../kill-leftover-processes/index.ts";
|
|
4
|
+
import { callTheSupervisor } from "./talk-to-the-supervisor.ts";
|
|
5
|
+
|
|
6
|
+
export const processGroupsSharedWithTheSupervisor = new Map<
|
|
7
|
+
number,
|
|
8
|
+
ReturnType<typeof startedProcessGroup>
|
|
9
|
+
>();
|
|
10
|
+
|
|
11
|
+
export const shareProcessGroups = (processGroupIds: Iterable<number>) =>
|
|
12
|
+
callTheSupervisor((supervisor) =>
|
|
13
|
+
Effect.forEach(
|
|
14
|
+
processGroupIds,
|
|
15
|
+
(processGroupId) =>
|
|
16
|
+
supervisor.ShareProcessGroup(
|
|
17
|
+
{
|
|
18
|
+
processGroupId,
|
|
19
|
+
startedGroup: processGroupsSharedWithTheSupervisor.get(processGroupId) ?? null,
|
|
20
|
+
},
|
|
21
|
+
{ discard: true },
|
|
22
|
+
),
|
|
23
|
+
{ discard: true },
|
|
24
|
+
),
|
|
25
|
+
);
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import * as BunSocketServer from "@effect/platform-bun/BunSocketServer";
|
|
2
|
+
import { Deferred, Duration, Effect, Exit, FileSystem, Path, Predicate, Ref, Stream } from "effect";
|
|
3
|
+
import type { Queue } from "effect";
|
|
4
|
+
import { RpcServer } from "effect/rpc";
|
|
5
|
+
import { SocketServer } from "effect/socket";
|
|
6
|
+
|
|
7
|
+
import { TASK_TRACE_LABEL_PREFIX } from "../../../shared/names-from-package-json.ts";
|
|
8
|
+
import { SupervisorSocketNotOpened } from "../../../shared/process-errors.ts";
|
|
9
|
+
import {
|
|
10
|
+
inheritedEnvironment,
|
|
11
|
+
inheritedRunMarkers,
|
|
12
|
+
RUN_MARKERS_VARIABLE_NAME,
|
|
13
|
+
supervisedRunCommand,
|
|
14
|
+
} from "../../../shared/read-environment-config.ts";
|
|
15
|
+
import { saveStandardStreamFlags } from "../../../shared/save-standard-stream-flags.ts";
|
|
16
|
+
import { listenToSignals } from "../../../shared/stop-signals.ts";
|
|
17
|
+
import type { STOP_SIGNALS } from "../../../shared/stop-signals.ts";
|
|
18
|
+
import { createRunMarker, signalRunProcesses } from "../../kill-leftover-processes/index.ts";
|
|
19
|
+
import type { startedProcessGroup } from "../../kill-leftover-processes/index.ts";
|
|
20
|
+
import { adoptOrphans } from "./adopt-orphans-on-linux.ts";
|
|
21
|
+
import { provideSupervisorRpcSerialization, SupervisorRpcs } from "./talk-to-the-supervisor.ts";
|
|
22
|
+
import { WATCH_THE_SUPERVISOR_FLAG } from "./watch-the-supervisor.ts";
|
|
23
|
+
|
|
24
|
+
const FORCED_STOP_GRACE_SECONDS = 5;
|
|
25
|
+
|
|
26
|
+
const FORCED_STOP_GRACE = Duration.seconds(FORCED_STOP_GRACE_SECONDS);
|
|
27
|
+
|
|
28
|
+
const SUPERVISOR_SOCKET_FILE_NAME = "supervisor.sock";
|
|
29
|
+
|
|
30
|
+
const serveTheRun = Effect.fn("serveTheRun")(
|
|
31
|
+
function* (
|
|
32
|
+
ready: Deferred.Deferred<void>,
|
|
33
|
+
startedProcessGroups: Map<number, ReturnType<typeof startedProcessGroup>>,
|
|
34
|
+
) {
|
|
35
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
36
|
+
const path = yield* Path.Path;
|
|
37
|
+
const socketPath = yield* fileSystem
|
|
38
|
+
.makeTempDirectoryScoped({ prefix: `${TASK_TRACE_LABEL_PREFIX}-supervisor-` })
|
|
39
|
+
.pipe(
|
|
40
|
+
Effect.map((socketDirectoryPath) =>
|
|
41
|
+
path.join(socketDirectoryPath, SUPERVISOR_SOCKET_FILE_NAME),
|
|
42
|
+
),
|
|
43
|
+
);
|
|
44
|
+
const socketServer = yield* BunSocketServer.make({ path: socketPath });
|
|
45
|
+
const handlers = yield* SupervisorRpcs.toHandlers({
|
|
46
|
+
ReportReady: () => Deferred.done(ready, Exit.void).pipe(Effect.asVoid),
|
|
47
|
+
ShareProcessGroup: (shared) =>
|
|
48
|
+
Effect.sync(() => {
|
|
49
|
+
if (shared.startedGroup === null) {
|
|
50
|
+
startedProcessGroups.delete(shared.processGroupId);
|
|
51
|
+
} else {
|
|
52
|
+
startedProcessGroups.set(shared.processGroupId, shared.startedGroup);
|
|
53
|
+
}
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
yield* RpcServer.make(SupervisorRpcs, { disableTracing: true }).pipe(
|
|
57
|
+
Effect.provideContext(handlers),
|
|
58
|
+
Effect.provideServiceEffect(RpcServer.Protocol, RpcServer.makeProtocolSocketServer),
|
|
59
|
+
Effect.provideService(SocketServer.SocketServer, socketServer),
|
|
60
|
+
provideSupervisorRpcSerialization,
|
|
61
|
+
Effect.interruptible,
|
|
62
|
+
Effect.forkScoped,
|
|
63
|
+
);
|
|
64
|
+
return socketPath;
|
|
65
|
+
},
|
|
66
|
+
Effect.mapError((cause) => new SupervisorSocketNotOpened({ cause })),
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
export const superviseRun = Effect.fn("superviseRun")(function* (
|
|
70
|
+
stopSignals: Queue.Dequeue<(typeof STOP_SIGNALS)[number]>,
|
|
71
|
+
) {
|
|
72
|
+
const reapAdoptedOrphans = yield* adoptOrphans;
|
|
73
|
+
const exited = yield* Deferred.make<NodeJS.Signals | number>();
|
|
74
|
+
const ready = yield* Deferred.make<void>();
|
|
75
|
+
const startedProcessGroups = new Map<number, ReturnType<typeof startedProcessGroup>>();
|
|
76
|
+
const command = yield* supervisedRunCommand(
|
|
77
|
+
WATCH_THE_SUPERVISOR_FLAG,
|
|
78
|
+
yield* serveTheRun(ready, startedProcessGroups),
|
|
79
|
+
);
|
|
80
|
+
const environment = yield* inheritedEnvironment;
|
|
81
|
+
const runMarker = yield* createRunMarker(yield* inheritedRunMarkers);
|
|
82
|
+
const restoreStandardStreamFlags = yield* saveStandardStreamFlags;
|
|
83
|
+
const child = yield* Effect.sync(() =>
|
|
84
|
+
Bun.spawn(command, {
|
|
85
|
+
detached: true,
|
|
86
|
+
stdio: [
|
|
87
|
+
"inherit",
|
|
88
|
+
"inherit",
|
|
89
|
+
"inherit",
|
|
90
|
+
...(runMarker === null ? [] : [runMarker.fileDescriptor]),
|
|
91
|
+
],
|
|
92
|
+
env:
|
|
93
|
+
runMarker === null
|
|
94
|
+
? environment
|
|
95
|
+
: Object.fromEntries(
|
|
96
|
+
Object.entries(environment).filter(([name]) => name !== RUN_MARKERS_VARIABLE_NAME),
|
|
97
|
+
),
|
|
98
|
+
onExit: (exitedChild, exitCode) => {
|
|
99
|
+
Deferred.doneUnsafe(exited, Exit.succeed(exitedChild.signalCode ?? exitCode ?? 1));
|
|
100
|
+
},
|
|
101
|
+
}),
|
|
102
|
+
);
|
|
103
|
+
yield* restoreStandardStreamFlags;
|
|
104
|
+
yield* reapAdoptedOrphans(child.pid);
|
|
105
|
+
const run = {
|
|
106
|
+
sessionId: child.pid,
|
|
107
|
+
descendantsOfProcessId: process.platform === "linux" ? process.pid : null,
|
|
108
|
+
startedProcessGroups,
|
|
109
|
+
runMarker,
|
|
110
|
+
};
|
|
111
|
+
const forced = yield* Deferred.make<void>();
|
|
112
|
+
const stopCount = yield* Ref.make(0);
|
|
113
|
+
yield* Stream.fromQueue(stopSignals).pipe(
|
|
114
|
+
Stream.runForEach((signal) =>
|
|
115
|
+
Ref.updateAndGet(stopCount, (count) => count + 1).pipe(
|
|
116
|
+
Effect.flatMap((count) => {
|
|
117
|
+
const forcesTheStop = signal === "SIGHUP" || count > 1;
|
|
118
|
+
const forward = Effect.sync(() => {
|
|
119
|
+
child.kill(signal);
|
|
120
|
+
});
|
|
121
|
+
return forcesTheStop
|
|
122
|
+
? forward.pipe(Effect.andThen(Deferred.done(forced, Exit.void)), Effect.asVoid)
|
|
123
|
+
: Deferred.await(ready).pipe(Effect.andThen(forward), Effect.forkScoped, Effect.asVoid);
|
|
124
|
+
}),
|
|
125
|
+
),
|
|
126
|
+
),
|
|
127
|
+
Effect.interruptible,
|
|
128
|
+
Effect.forkScoped,
|
|
129
|
+
);
|
|
130
|
+
const jobControlSignals = yield* listenToSignals(["SIGTSTP", "SIGCONT"]);
|
|
131
|
+
yield* Stream.fromQueue(jobControlSignals).pipe(
|
|
132
|
+
Stream.runForEach((signal) =>
|
|
133
|
+
signal === "SIGTSTP"
|
|
134
|
+
? signalRunProcesses(run, "SIGSTOP").pipe(
|
|
135
|
+
Effect.andThen(Effect.sync(() => process.kill(process.pid, "SIGSTOP"))),
|
|
136
|
+
)
|
|
137
|
+
: signalRunProcesses(run, "SIGCONT"),
|
|
138
|
+
),
|
|
139
|
+
Effect.interruptible,
|
|
140
|
+
Effect.forkScoped,
|
|
141
|
+
);
|
|
142
|
+
yield* Deferred.await(exited).pipe(
|
|
143
|
+
Effect.raceFirst(
|
|
144
|
+
Deferred.await(forced).pipe(
|
|
145
|
+
Effect.andThen(Deferred.await(exited).pipe(Effect.timeoutOption(FORCED_STOP_GRACE))),
|
|
146
|
+
),
|
|
147
|
+
),
|
|
148
|
+
);
|
|
149
|
+
const runSkippedItsCleanup =
|
|
150
|
+
(yield* Deferred.isDone(forced)) || Predicate.isString(yield* Deferred.await(exited));
|
|
151
|
+
if (runSkippedItsCleanup) {
|
|
152
|
+
yield* signalRunProcesses(run, "SIGKILL");
|
|
153
|
+
}
|
|
154
|
+
return yield* Deferred.await(exited);
|
|
155
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as BunSocket from "@effect/platform-bun/BunSocket";
|
|
2
|
+
import { Deferred, Duration, Effect, Schema } from "effect";
|
|
3
|
+
import { Rpc, RpcClient, RpcGroup, RpcSerialization } from "effect/rpc";
|
|
4
|
+
import type { RpcClientError } from "effect/rpc";
|
|
5
|
+
import { Socket } from "effect/socket";
|
|
6
|
+
|
|
7
|
+
export const ProcessGroupShared = Schema.Struct({
|
|
8
|
+
processGroupId: Schema.Int,
|
|
9
|
+
startedGroup: Schema.NullOr(
|
|
10
|
+
Schema.Struct({
|
|
11
|
+
taskName: Schema.String,
|
|
12
|
+
leaderStartTime: Schema.NullOr(Schema.String),
|
|
13
|
+
latestMemberStartTimeAtLeaderExit: Schema.NullOr(Schema.String),
|
|
14
|
+
}),
|
|
15
|
+
),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export const SupervisorRpcs = RpcGroup.make(
|
|
19
|
+
Rpc.make("ReportReady"),
|
|
20
|
+
Rpc.make("ShareProcessGroup", { payload: ProcessGroupShared }),
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
export const provideSupervisorRpcSerialization = Effect.provideService(
|
|
24
|
+
RpcSerialization.RpcSerialization,
|
|
25
|
+
RpcSerialization.ndjson,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export const connectToTheSupervisor = (
|
|
29
|
+
supervisorSocketPath: string,
|
|
30
|
+
onDisconnect: Effect.Effect<void>,
|
|
31
|
+
) =>
|
|
32
|
+
RpcClient.make(SupervisorRpcs, { disableTracing: true }).pipe(
|
|
33
|
+
Effect.provideServiceEffect(
|
|
34
|
+
RpcClient.Protocol,
|
|
35
|
+
RpcClient.makeProtocolSocket({ pingInterval: Duration.infinity }),
|
|
36
|
+
),
|
|
37
|
+
Effect.provideService(RpcClient.ConnectionHooks, { onConnect: Effect.void, onDisconnect }),
|
|
38
|
+
Effect.provideServiceEffect(Socket.Socket, BunSocket.makeNet({ path: supervisorSocketPath })),
|
|
39
|
+
provideSupervisorRpcSerialization,
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
export const supervisorConnectionDeferred =
|
|
43
|
+
Deferred.makeUnsafe<Effect.Success<ReturnType<typeof connectToTheSupervisor>>>();
|
|
44
|
+
|
|
45
|
+
export const callTheSupervisor = (
|
|
46
|
+
call: (
|
|
47
|
+
supervisor: Effect.Success<ReturnType<typeof connectToTheSupervisor>>,
|
|
48
|
+
) => Effect.Effect<void, RpcClientError.RpcClientError>,
|
|
49
|
+
) =>
|
|
50
|
+
Deferred.await(supervisorConnectionDeferred).pipe(
|
|
51
|
+
Effect.flatMap(call),
|
|
52
|
+
Effect.catchTag("RpcClientError", () => Effect.void),
|
|
53
|
+
);
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Deferred, Effect, Exit, Option, Ref, Stdio, Stream } from "effect";
|
|
2
|
+
|
|
3
|
+
import { formatFailureLines } from "../../../shared/format-error-lines.ts";
|
|
4
|
+
import { takeSupervisorSocketPath } from "../../../shared/read-environment-config.ts";
|
|
5
|
+
import type { RunMarker } from "../../../shared/run-marker.ts";
|
|
6
|
+
import {
|
|
7
|
+
adoptSupervisorRunMarker,
|
|
8
|
+
signalRunProcesses,
|
|
9
|
+
} from "../../kill-leftover-processes/index.ts";
|
|
10
|
+
import { processGroupsSharedWithTheSupervisor } from "./share-process-groups.ts";
|
|
11
|
+
import { connectToTheSupervisor, supervisorConnectionDeferred } from "./talk-to-the-supervisor.ts";
|
|
12
|
+
|
|
13
|
+
export const WATCH_THE_SUPERVISOR_FLAG = `--preload=${Bun.fileURLToPath(import.meta.resolve("./start-watching-the-supervisor.ts"))}`;
|
|
14
|
+
|
|
15
|
+
export const supervisorProcessId = Ref.makeUnsafe<number | null>(null);
|
|
16
|
+
|
|
17
|
+
export const supervisorRunMarker = Ref.makeUnsafe<typeof RunMarker.Type | null>(null);
|
|
18
|
+
|
|
19
|
+
export const watchSupervisor = Effect.gen(function* () {
|
|
20
|
+
yield* Effect.sync(() =>
|
|
21
|
+
process.execArgv.splice(process.execArgv.indexOf(WATCH_THE_SUPERVISOR_FLAG), 1),
|
|
22
|
+
);
|
|
23
|
+
const supervisorSocketPath = yield* takeSupervisorSocketPath;
|
|
24
|
+
if (Option.isNone(supervisorSocketPath)) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
yield* Ref.set(supervisorProcessId, process.ppid);
|
|
28
|
+
const stdio = yield* Stdio.Stdio;
|
|
29
|
+
const printFailure = (error: Parameters<typeof formatFailureLines>[0]) =>
|
|
30
|
+
Stream.make(`${formatFailureLines(error, null)}\n`).pipe(Stream.run(stdio.stderr()));
|
|
31
|
+
const runMarker = yield* adoptSupervisorRunMarker.pipe(
|
|
32
|
+
Effect.catchTag(["ProcRunMarkerUnreadable", "SystemLibraryNotLoaded"], (error) =>
|
|
33
|
+
printFailure(error).pipe(Effect.as(null)),
|
|
34
|
+
),
|
|
35
|
+
);
|
|
36
|
+
yield* Ref.set(supervisorRunMarker, runMarker);
|
|
37
|
+
const disconnected = yield* Deferred.make<void>();
|
|
38
|
+
const supervisor = yield* connectToTheSupervisor(
|
|
39
|
+
supervisorSocketPath.value,
|
|
40
|
+
Deferred.done(disconnected, Exit.void).pipe(Effect.asVoid),
|
|
41
|
+
);
|
|
42
|
+
yield* Deferred.succeed(supervisorConnectionDeferred, supervisor);
|
|
43
|
+
yield* Deferred.await(disconnected).pipe(
|
|
44
|
+
Effect.andThen(
|
|
45
|
+
signalRunProcesses(
|
|
46
|
+
{
|
|
47
|
+
sessionId: process.pid,
|
|
48
|
+
descendantsOfProcessId: process.pid,
|
|
49
|
+
startedProcessGroups: processGroupsSharedWithTheSupervisor,
|
|
50
|
+
runMarker,
|
|
51
|
+
},
|
|
52
|
+
"SIGKILL",
|
|
53
|
+
),
|
|
54
|
+
),
|
|
55
|
+
Effect.matchEffect({
|
|
56
|
+
onFailure: (error) => printFailure(error),
|
|
57
|
+
onSuccess: (success) => Effect.succeed(success),
|
|
58
|
+
}),
|
|
59
|
+
Effect.ensuring(Effect.sync(() => process.kill(process.pid, "SIGKILL"))),
|
|
60
|
+
);
|
|
61
|
+
}).pipe(Effect.scoped);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { make, Task } from "./internal/make-tasks.ts";
|
|
2
|
+
export { exec } from "./internal/run-command.ts";
|
|
3
|
+
export { main } from "./internal/run-root-task.ts";
|
|
4
|
+
export { all, allSettled } from "./internal/run-task-lists.ts";
|
|
5
|
+
export { serve } from "./internal/use-task-services.ts";
|