chore(workflow): post-extraction cleanup #326
+2
-1
@@ -7,7 +7,8 @@
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"@uncaged/nerve-core": "workspace:*",
|
||||
"@uncaged/nerve-store": "workspace:*"
|
||||
"@uncaged/nerve-store": "workspace:*",
|
||||
"@uncaged/workflow": "workspace:*"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"test": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@uncaged/workflow": "workspace:*",
|
||||
"yaml": "^2.8.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,23 +1,9 @@
|
||||
import { parse } from "yaml";
|
||||
|
||||
import type { DropOverflowConfig, QueueOverflowConfig, WorkflowConfig } from "@uncaged/workflow";
|
||||
import { type Result, err, isPlainRecord, ok, parseDurationStringToMs } from "./util.js";
|
||||
|
||||
/**
|
||||
* Workflow queue/runtime limits parsed from nerve.yaml.
|
||||
* Shapes match the standalone workflow package — core must not depend on it (#320).
|
||||
*/
|
||||
export type DropOverflowConfig = {
|
||||
concurrency: number;
|
||||
overflow: "drop";
|
||||
};
|
||||
|
||||
export type QueueOverflowConfig = {
|
||||
concurrency: number;
|
||||
overflow: "queue";
|
||||
maxQueue: number;
|
||||
};
|
||||
|
||||
export type WorkflowConfig = DropOverflowConfig | QueueOverflowConfig;
|
||||
export type { DropOverflowConfig, QueueOverflowConfig, WorkflowConfig };
|
||||
|
||||
/** Engine-wide fallback when nerve.yaml omits max_rounds (keep in sync with workflow package default). */
|
||||
export const DEFAULT_ENGINE_MAX_ROUNDS = 100;
|
||||
|
||||
@@ -32,7 +32,6 @@ export type {
|
||||
WorkflowWorkerToParentMessage,
|
||||
WorkflowWorkerReadyMessage,
|
||||
WorkflowChildToParentMessage,
|
||||
WorkflowWorkerOutboundMessage,
|
||||
} from "./ipc.js";
|
||||
export {
|
||||
parseWorkflowParentMessage,
|
||||
|
||||
@@ -100,11 +100,6 @@ export type WorkflowChildToParentMessage =
|
||||
| WorkflowWorkerReadyMessage
|
||||
| WorkflowWorkerToParentMessage;
|
||||
|
||||
/** Messages a workflow worker process may send upstream (ready + persisted workflow IPC). */
|
||||
export type WorkflowWorkerOutboundMessage =
|
||||
| WorkflowWorkerReadyMessage
|
||||
| WorkflowWorkerToParentMessage;
|
||||
|
||||
const WORKFLOW_PARENT_MSG_TYPES = new Set([
|
||||
"start-thread",
|
||||
"resume-thread",
|
||||
@@ -135,12 +130,12 @@ function parseParentStartThread(obj: Record<string, unknown>): Result<StartThrea
|
||||
if (errMsg !== null) return err(new Error(errMsg));
|
||||
return ok({
|
||||
type: "start-thread",
|
||||
runId: obj.runId,
|
||||
workflow: obj.workflow,
|
||||
prompt: obj.prompt,
|
||||
maxRounds: obj.maxRounds,
|
||||
dryRun: obj.dryRun,
|
||||
} as StartThreadMessage);
|
||||
runId: obj.runId as string,
|
||||
workflow: obj.workflow as string,
|
||||
prompt: obj.prompt as string,
|
||||
maxRounds: obj.maxRounds as number,
|
||||
dryRun: obj.dryRun as boolean,
|
||||
});
|
||||
}
|
||||
|
||||
function parseParentResumeThread(obj: Record<string, unknown>): Result<ResumeThreadMessage> {
|
||||
@@ -148,18 +143,18 @@ function parseParentResumeThread(obj: Record<string, unknown>): Result<ResumeThr
|
||||
if (errMsg !== null) return err(new Error(errMsg));
|
||||
return ok({
|
||||
type: "resume-thread",
|
||||
runId: obj.runId,
|
||||
runId: obj.runId as string,
|
||||
messages: obj.messages as ResumeThreadMessage["messages"],
|
||||
maxRounds: obj.maxRounds,
|
||||
dryRun: obj.dryRun,
|
||||
} as ResumeThreadMessage);
|
||||
maxRounds: obj.maxRounds as number,
|
||||
dryRun: obj.dryRun as boolean,
|
||||
});
|
||||
}
|
||||
|
||||
function parseParentKillThread(obj: Record<string, unknown>): Result<KillThreadMessage> {
|
||||
if (typeof obj.runId !== "string") {
|
||||
return err(new Error("'kill-thread' message missing string 'runId'"));
|
||||
}
|
||||
return ok({ type: "kill-thread", runId: obj.runId } as KillThreadMessage);
|
||||
return ok({ type: "kill-thread", runId: obj.runId as string });
|
||||
}
|
||||
|
||||
/** Validate and parse an unknown IPC message for a workflow worker process. */
|
||||
|
||||
@@ -58,8 +58,9 @@ export type WorkflowManager = {
|
||||
* Drain active threads for a workflow, then respawn its worker process.
|
||||
* Used for hot reload when bundled workflow output under dist/workflows/<name>/ changes.
|
||||
* Waits up to `drainTimeoutMs` for threads to complete before force-killing.
|
||||
* Pass `null` to use the manager default timeout.
|
||||
*/
|
||||
drainAndRespawn: (workflowName: string, drainTimeoutMs?: number) => Promise<void>;
|
||||
drainAndRespawn: (workflowName: string, drainTimeoutMs?: number | null) => Promise<void>;
|
||||
/**
|
||||
* Schedule a drain+respawn that waits for in-flight runs to finish first.
|
||||
* If no runs are active, drains immediately. Otherwise marks a pending reload
|
||||
@@ -450,13 +451,16 @@ export function createWorkflowManager(
|
||||
|
||||
async function drainAndRespawn(
|
||||
workflowName: string,
|
||||
drainTimeoutMs: number = DEFAULT_DRAIN_TIMEOUT_MS,
|
||||
drainTimeoutMs: number | null = null,
|
||||
): Promise<void> {
|
||||
if (!trackedWorkflows.has(workflowName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const shutdownMs = Math.max(drainTimeoutMs, WORKER_SHUTDOWN_TIMEOUT_MS);
|
||||
const shutdownMs = Math.max(
|
||||
drainTimeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS,
|
||||
WORKER_SHUTDOWN_TIMEOUT_MS,
|
||||
);
|
||||
hotReloadEvicting.add(workflowName);
|
||||
try {
|
||||
await runtime.evict(workflowName, { shutdownTimeoutMs: shutdownMs });
|
||||
|
||||
@@ -19,7 +19,7 @@ import { isPlainRecord } from "@uncaged/nerve-core";
|
||||
import type {
|
||||
ThreadEventType,
|
||||
ThreadWorkflowMessage,
|
||||
WorkflowWorkerOutboundMessage,
|
||||
WorkflowChildToParentMessage,
|
||||
} from "./ipc.js";
|
||||
import { parseWorkflowParentMessage } from "./ipc.js";
|
||||
import type {
|
||||
@@ -37,7 +37,7 @@ import { ignoreSessionBroadcastSignals } from "./worker-signals.js";
|
||||
// IPC helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function send(msg: WorkflowWorkerOutboundMessage): void {
|
||||
function send(msg: WorkflowChildToParentMessage): void {
|
||||
if (process.send) {
|
||||
process.send(msg);
|
||||
}
|
||||
|
||||
Generated
+4
@@ -7,6 +7,7 @@ settings:
|
||||
overrides:
|
||||
'@uncaged/nerve-core': workspace:*
|
||||
'@uncaged/nerve-store': workspace:*
|
||||
'@uncaged/workflow': workspace:*
|
||||
|
||||
importers:
|
||||
|
||||
@@ -99,6 +100,9 @@ importers:
|
||||
|
||||
packages/core:
|
||||
dependencies:
|
||||
'@uncaged/workflow':
|
||||
specifier: workspace:*
|
||||
version: link:../workflow
|
||||
yaml:
|
||||
specifier: ^2.8.3
|
||||
version: 2.8.3
|
||||
|
||||
Reference in New Issue
Block a user