@cloud-cli/on 1.8.1 → 1.9.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/README.md +11 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/events.d.ts +12 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/on.js +214 -78
- package/dist/parser/yaml-loader.d.ts.map +1 -1
- package/dist/queue.d.ts +3 -2
- package/dist/queue.d.ts.map +1 -1
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/worker.d.ts +3 -2
- package/dist/worker.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -82,6 +82,9 @@ concurrency:
|
|
|
82
82
|
group: release-${inputs.repo}
|
|
83
83
|
cancel-in-progress: true
|
|
84
84
|
|
|
85
|
+
# Every tag must be advertised by the worker that claims this workflow.
|
|
86
|
+
tags: [linux, docker]
|
|
87
|
+
|
|
85
88
|
steps:
|
|
86
89
|
- id: checkout
|
|
87
90
|
name: Checkout Code Repository
|
|
@@ -147,7 +150,7 @@ npx @cloud-cli/on [command] [options]
|
|
|
147
150
|
| Command | Description |
|
|
148
151
|
| ------------------- | ---------------------------------------------------------------------------------------- |
|
|
149
152
|
| **`start-server`** | Runs Webhook Ingress Gateway (the HTTP server receiving webhooks). |
|
|
150
|
-
| **`start-workers`** | Runs
|
|
153
|
+
| **`start-workers`** | Runs the event-driven worker scheduler (Scalable Workers). |
|
|
151
154
|
| **`validate`** | Parses and validates all YAML workflows in your workflows folder without executing jobs. |
|
|
152
155
|
|
|
153
156
|
### CLI and Environment Options
|
|
@@ -159,8 +162,12 @@ npx @cloud-cli/on [command] [options]
|
|
|
159
162
|
| `-d` | `--database` | - | `RUNNER_DATABASE_URL` | SQLite database file path or HTTP URL. |
|
|
160
163
|
| `-w` | `--workflows` | `on/` | `RUNNER_WORKFLOWS` | Directory where workflow YAML files live. |
|
|
161
164
|
| `-p` | `--port` | `11235` | `PORT` | Port for the Ingress HTTP server. |
|
|
162
|
-
| `-k` | `--workers` | `5` | `RUNNER_WORKERS` |
|
|
165
|
+
| `-k` | `--workers` | `5` | `RUNNER_WORKERS` | Maximum concurrent jobs on this node. |
|
|
163
166
|
| | | | `RUNNER_ADMIN_SECRET` | Admin token to refresh secrets via API |
|
|
167
|
+
| | | | `RUNNER_SERVER_URL` | Webhook server URL used by workers. |
|
|
168
|
+
| | | | `RUNNER_TAGS` | Comma-separated worker capability tags. |
|
|
169
|
+
|
|
170
|
+
Set the same non-empty `RUNNER_ADMIN_SECRET` on the server and workers to publish live job-status refresh events. Job availability and the 60-second recovery refresh continue to work without it.
|
|
164
171
|
|
|
165
172
|
### Secrets
|
|
166
173
|
|
|
@@ -177,6 +184,8 @@ import { HtmlReporter, SlackReporter, JsonFileReporter } from '@cloud-cli/on/rep
|
|
|
177
184
|
export default {
|
|
178
185
|
port: 3000,
|
|
179
186
|
workers: 5,
|
|
187
|
+
serverUrl: 'https://runner.example.com/',
|
|
188
|
+
tags: ['linux', 'docker'],
|
|
180
189
|
workflows: '/home/workflows/',
|
|
181
190
|
storagePath: '/tmp/workspaces',
|
|
182
191
|
database: 'https://remote.db.com/',
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG5D,wBAAsB,UAAU,CAAC,MAAM,KAAA,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAyBrE;AAED,wBAAgB,aAAa,CAAC,cAAc,EAAE,gBAAgB,EAAE,aAAa,EAAE,gBAAgB,GAAG,YAAY,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG5D,wBAAsB,UAAU,CAAC,MAAM,KAAA,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAyBrE;AAED,wBAAgB,aAAa,CAAC,cAAc,EAAE,gBAAgB,EAAE,aAAa,EAAE,gBAAgB,GAAG,YAAY,CAgB7G;AAED,wBAAgB,SAAS,SAwBxB;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAwB9F"}
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type http from 'node:http';
|
|
2
|
+
export type RunnerEvent = 'jobs.available' | 'jobs.changed';
|
|
3
|
+
export declare class EventBroker {
|
|
4
|
+
private clients;
|
|
5
|
+
private nextId;
|
|
6
|
+
private readonly maxClients;
|
|
7
|
+
subscribe(req: http.IncomingMessage, res: http.ServerResponse): void;
|
|
8
|
+
publish(event: RunnerEvent, data?: Record<string, unknown>): void;
|
|
9
|
+
close(): void;
|
|
10
|
+
}
|
|
11
|
+
export declare function consumeRunnerEvents(serverUrl: string, signal: AbortSignal, onEvent: (event: RunnerEvent, data: Record<string, unknown>) => void, onOpen?: () => void): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,MAAM,MAAM,WAAW,GAAG,gBAAgB,GAAG,cAAc,CAAC;AAE5D,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAkD;IACjE,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAQ;IAEnC,SAAS,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,GAAG,IAAI;IAuBpE,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,IAAI;IAUrE,KAAK,IAAI,IAAI;CAOd;AAED,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,EACnB,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,EACpE,MAAM,CAAC,EAAE,MAAM,IAAI,GAClB,OAAO,CAAC,IAAI,CAAC,CA4Bf"}
|
package/dist/on.js
CHANGED
|
@@ -63,20 +63,22 @@ async function le(e) {
|
|
|
63
63
|
return t(o.workflows) ? (ce(o.database), o) : (console.warn(`⚠️ Warning: Workflows directory '${o.workflows}' not found.`), null);
|
|
64
64
|
}
|
|
65
65
|
function ue(e, t) {
|
|
66
|
-
let n = process.env;
|
|
66
|
+
let n = process.env, r = Number(e.port || t.port || n.PORT || 11235), i = e.tags ?? (n.RUNNER_TAGS ? n.RUNNER_TAGS.split(",") : []);
|
|
67
67
|
return {
|
|
68
|
-
port:
|
|
68
|
+
port: r,
|
|
69
69
|
adminToken: e.adminToken ?? n.RUNNER_ADMIN_SECRET ?? "",
|
|
70
70
|
database: e.database ?? t.database ?? n.RUNNER_DATABASE_URL ?? "",
|
|
71
71
|
workflows: e.workflows ?? t.workflows ?? n.RUNNER_WORKFLOWS ?? "on/",
|
|
72
72
|
workers: Number(e.workers ?? t.workers ?? n.RUNNER_WORKERS ?? 5),
|
|
73
|
+
serverUrl: e.serverUrl ?? n.RUNNER_SERVER_URL ?? `http://127.0.0.1:${r}`,
|
|
74
|
+
tags: i.map((e) => e.trim()).filter(Boolean),
|
|
73
75
|
storagePath: e.storagePath ?? n.RUNNER_TMP ?? "/tmp/workspaces",
|
|
74
76
|
env: e.env ?? {},
|
|
75
77
|
reporters: e.reporters ?? []
|
|
76
78
|
};
|
|
77
79
|
}
|
|
78
80
|
function de() {
|
|
79
|
-
console.log("\n🏃 Runner CLI 🏃\n\nUsage:\n npx -y @cloud-cli/on <command> [options]\n pnpm dlx -y @cloud-cli/on <command> [options]\n\nCommands:\n start Runs both Webhook Ingress Server and Workers (Default)\n start-server Runs Webhook Ingress Server only (API Gateway mode)\n start-workers Runs
|
|
81
|
+
console.log("\n🏃 Runner CLI 🏃\n\nUsage:\n npx -y @cloud-cli/on <command> [options]\n pnpm dlx -y @cloud-cli/on <command> [options]\n\nCommands:\n start Runs both Webhook Ingress Server and Workers (Default)\n start-server Runs Webhook Ingress Server only (API Gateway mode)\n start-workers Runs event-driven workers (Scalable Worker mode)\n validate Parses and validates workflow YAML files without running\n\nOptions:\n -c, --config Path to runner.config.mjs (default: ./runner.config.mjs, env: RUNNER_CONFIG_PATH)\n -d, --database SQLite Database URL (env: RUNNER_DATABASE_URL)\n -w, --workflows Path to where your workflows are defined (default: on/, env: RUNNER_WORKFLOWS_PATH)\n -p, --port Port for Webhook Ingress Server (default: 11235, env: PORT)\n -k, --workers Maximum concurrent jobs (default: 5, env: RUNNER_WORKERS)\n Worker tags (comma-separated env: RUNNER_TAGS)\n Webhook server URL (env: RUNNER_SERVER_URL)\n -h, --help Show this help message\n ");
|
|
80
82
|
}
|
|
81
83
|
async function fe() {
|
|
82
84
|
let { values: e, positionals: t } = l({
|
|
@@ -4462,8 +4464,11 @@ var pi = class {
|
|
|
4462
4464
|
JSON.stringify(t)
|
|
4463
4465
|
]);
|
|
4464
4466
|
}
|
|
4465
|
-
async claimNextJob() {
|
|
4466
|
-
return await S.get("\n UPDATE jobs\n SET\n status = 'running',\n worker_id = ?,\n started_at = CURRENT_TIMESTAMP\n WHERE id = (\n SELECT id FROM jobs\n WHERE status = 'pending'\n ORDER BY created_at ASC\n LIMIT 1\n )\n RETURNING *;\n ", [this.workerId]) || null;
|
|
4467
|
+
async claimNextJob(e = []) {
|
|
4468
|
+
return await S.get("\n UPDATE jobs\n SET\n status = 'running',\n worker_id = ?,\n started_at = CURRENT_TIMESTAMP\n WHERE id = (\n SELECT id FROM jobs\n WHERE status = 'pending'\n AND NOT EXISTS (\n SELECT 1\n FROM json_each(COALESCE(json_extract(jobs.payload, '$.tags'), '[]')) AS required_tag\n WHERE required_tag.value NOT IN (SELECT value FROM json_each(?))\n )\n ORDER BY created_at ASC\n LIMIT 1\n )\n RETURNING *;\n ", [this.workerId, JSON.stringify(e)]) || null;
|
|
4469
|
+
}
|
|
4470
|
+
async releaseJob(e) {
|
|
4471
|
+
await S.run("UPDATE jobs SET status = 'pending', worker_id = NULL, started_at = NULL WHERE id = ? AND status = 'running';", [e]);
|
|
4467
4472
|
}
|
|
4468
4473
|
async finishJob(e, t) {
|
|
4469
4474
|
await S.run("UPDATE jobs SET status = ?, finished_at = CURRENT_TIMESTAMP WHERE id = ?;", [t, e]);
|
|
@@ -8024,7 +8029,8 @@ var Po = "<!DOCTYPE html>\n<html lang=\"en\" class=\"dark\">\n<head>\n <meta ch
|
|
|
8024
8029
|
},
|
|
8025
8030
|
concurrency: t.concurrency,
|
|
8026
8031
|
steps: t.steps,
|
|
8027
|
-
env: t.env
|
|
8032
|
+
env: t.env,
|
|
8033
|
+
tags: Array.isArray(t.tags) ? [...new Set(t.tags.filter((e) => typeof e == "string").map((e) => e.trim()).filter(Boolean))] : void 0
|
|
8028
8034
|
});
|
|
8029
8035
|
}
|
|
8030
8036
|
} catch (t) {
|
|
@@ -8032,7 +8038,7 @@ var Po = "<!DOCTYPE html>\n<html lang=\"en\" class=\"dark\">\n<head>\n <meta ch
|
|
|
8032
8038
|
}
|
|
8033
8039
|
return n;
|
|
8034
8040
|
}
|
|
8035
|
-
}, Ro = "<!DOCTYPE html>\n<html lang=\"en\" class=\"dark\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Workflow Engine Dashboard</title>\n <script type=\"importmap\">\n { \"imports\": { \"@li3/\": \"https://cdn.li3.dev/@li3/\" } }\n <\/script>\n</head>\n<body class=\"bg-gray-950 text-gray-100 min-h-screen p-4 md:p-6 font-sans\">\n <template app>\n <main class=\"max-w-6xl mx-auto space-y-6\">\n <header class=\"flex flex-col sm:flex-row sm:items-center justify-between gap-3 border-b border-gray-800 pb-4\">\n <div>\n <h1 class=\"text-2xl font-bold text-white\">Runner Engine Status</h1>\n <p class=\"text-xs text-gray-400\">Live Job Queue & Execution Traces</p>\n </div>\n <div class=\"flex items-center gap-3 text-xs font-mono\">\n <span class=\"text-gray-500\">Updated {{ lastUpdated }}</span>\n <span\n class=\"px-3 py-1 rounded-full border\"\n bind-class=\"{\n 'bg-emerald-500/10.text-emerald-400.border-emerald-500/20': !refreshError,\n 'bg-rose-500/10.text-rose-400.border-rose-500/20': refreshError\n }\"\n >\n {{ refreshError ? 'Refresh failed' : 'System operational' }}\n </span>\n </div>\n </header>\n\n <section class=\"bg-gray-900 border border-gray-800 rounded-xl overflow-hidden hidden md:block\">\n <table class=\"w-full text-left text-sm\">\n <thead class=\"bg-gray-800/50 text-gray-400 text-xs uppercase font-mono border-b border-gray-800\">\n <tr>\n <th class=\"py-3 px-4\">Job ID</th>\n <th class=\"py-3 px-4\">Workflow</th>\n <th class=\"py-3 px-4\">Status</th>\n <th class=\"py-3 px-4 hidden xl:table-cell\">Worker</th>\n <th class=\"py-3 px-4 hidden lg:table-cell\">Created At</th>\n <th class=\"py-3 px-4 text-right\">Action</th>\n </tr>\n </thead>\n <tbody>\n <template for=\"job of jobs\">\n <tr class=\"border-b border-gray-800 hover:bg-gray-800/40 transition\">\n <td class=\"py-3 px-4 font-mono text-indigo-400\">\n <a attr-href=\"'/runs/' + job.id\" class=\"hover:underline\">#{{ job.id }}</a>\n </td>\n <td class=\"py-3 px-4 font-medium text-white\">{{ job.workflowId }}</td>\n <td class=\"py-3 px-4\">\n <span\n class=\"px-2.5 py-0.5 rounded-full text-xs font-semibold\"\n bind-class=\"{\n 'bg-emerald-500/10.text-emerald-400': job.status === 'success',\n 'bg-rose-500/10.text-rose-400': job.status === 'failed',\n 'bg-indigo-500/10.text-indigo-400.animate-pulse': job.status === 'running',\n 'bg-gray-500/10.text-gray-400': !['success', 'failed', 'running'].includes(job.status)\n }\"\n >\n {{ upper(job.status) }}\n </span>\n </td>\n <td class=\"py-3 px-4 hidden xl:table-cell text-xs font-mono text-gray-400\">{{ job.workerId || '-' }}</td>\n <td class=\"py-3 px-4 hidden lg:table-cell text-xs text-gray-400\">{{ job.createdAt }}</td>\n <td class=\"py-3 px-4 text-right whitespace-nowrap\">\n <a attr-href=\"'/runs/' + job.id\" class=\"text-xs bg-gray-800 hover:bg-gray-700 text-gray-200 px-3 py-1 rounded border border-gray-700\">View Trace</a>\n </td>\n </tr>\n </template>\n </tbody>\n </table>\n <template if=\"!jobs.length\">\n <div class=\"p-8 text-center text-gray-500\">No jobs recorded yet.</div>\n </template>\n </section>\n\n <section class=\"md:hidden bg-gray-900 border border-gray-800 rounded-xl divide-y divide-gray-800 overflow-hidden\">\n <template for=\"job of jobs\">\n <article class=\"p-4 bg-gray-900/60\">\n <div class=\"flex items-start justify-between gap-3\">\n <div class=\"min-w-0\">\n <div class=\"flex items-center gap-2\">\n <span\n class=\"w-2.5 h-2.5 rounded-full shrink-0\"\n bind-class=\"{\n 'bg-emerald-400': job.status === 'success',\n 'bg-rose-400': job.status === 'failed',\n 'bg-indigo-400.animate-pulse': job.status === 'running',\n 'bg-gray-500': !['success', 'failed', 'running'].includes(job.status)\n }\"\n ></span>\n <h2 class=\"font-medium text-white truncate\">{{ job.workflowId }}</h2>\n </div>\n <p class=\"mt-1 pl-[18px] text-xs font-mono text-gray-400\">#{{ job.id }} · {{ upper(job.status) }}</p>\n </div>\n <a attr-href=\"'/runs/' + job.id\" class=\"shrink-0 text-xs bg-gray-800 hover:bg-gray-700 text-gray-300 px-2.5 py-1 rounded border border-gray-700\">Trace</a>\n </div>\n </article>\n </template>\n <template if=\"!jobs.length\">\n <div class=\"p-8 text-center text-gray-500\">No jobs recorded yet.</div>\n </template>\n </section>\n\n <template if=\"hasMore\">\n <div class=\"flex justify-center\">\n <button\n class=\"px-4 py-2 text-sm text-gray-200 bg-gray-800 hover:bg-gray-700 border border-gray-700 rounded-lg\"\n on-click=\"loadMore()\"\n >\n {{ loadingMore ? 'Loading...' : 'Load more' }}\n </button>\n </div>\n </template>\n </main>\n\n <script setup>\n import { onDestroy, onInit, ref } from '@li3/web';\n\n export default function setup() {\n const jobs = ref([]);\n const lastUpdated = ref('now');\n const refreshError = ref(false);\n const hasMore = ref(false);\n const loadingMore = ref(false);\n let refreshTimer;\n let refreshing = false;\n\n const upper = (value) => String(value || '').toUpperCase();\n const terminalStatuses = new Set(['success', 'failed', 'cancelled']);\n const refreshJobs = async () => {\n if (refreshing) return;\n refreshing = true;\n\n try {\n const activeIds = jobs.value\n .filter((job) => !terminalStatuses.has(job.status))\n .map((job) => Number(job.id));\n const knownIds = jobs.value.map((job) => Number(job.id));\n const afterId = activeIds.length\n ? Math.max(0, Math.min(...activeIds) - 1)\n : knownIds.length\n ? Math.max(...knownIds)\n : null;\n const url = afterId === null ? '/api/jobs?limit=500' : `/api/jobs?afterId=${afterId}&limit=500`;\n const response = await fetch(url, { headers: { accept: 'application/json' } });\n if (!response.ok) throw new Error(`Dashboard refresh failed: ${response.status}`);\n\n const data = await response.json();\n const merged = new Map(jobs.value.map((job) => [job.id, job]));\n for (const job of data.jobs) merged.set(job.id, job);\n jobs.value = Array.from(merged.values()).sort((a, b) => Number(b.id) - Number(a.id));\n lastUpdated.value = new Date().toLocaleTimeString();\n refreshError.value = false;\n } catch (error) {\n console.error(error);\n refreshError.value = true;\n } finally {\n refreshing = false;\n }\n };\n\n const loadMore = async () => {\n if (loadingMore.value || !hasMore.value || !jobs.value.length) return;\n loadingMore.value = true;\n\n try {\n const beforeId = Math.min(...jobs.value.map((job) => Number(job.id)));\n const response = await fetch(`/api/jobs?beforeId=${beforeId}`, {\n headers: { accept: 'application/json' },\n });\n if (!response.ok) throw new Error(`Loading older jobs failed: ${response.status}`);\n\n const data = await response.json();\n const merged = new Map(jobs.value.map((job) => [job.id, job]));\n for (const job of data.jobs) merged.set(job.id, job);\n jobs.value = Array.from(merged.values()).sort((a, b) => Number(b.id) - Number(a.id));\n hasMore.value = data.hasMore;\n } catch (error) {\n console.error(error);\n refreshError.value = true;\n } finally {\n loadingMore.value = false;\n }\n };\n\n onInit(() => {\n refreshTimer = setInterval(refreshJobs,
|
|
8041
|
+
}, Ro = "<!DOCTYPE html>\n<html lang=\"en\" class=\"dark\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Workflow Engine Dashboard</title>\n <script type=\"importmap\">\n { \"imports\": { \"@li3/\": \"https://cdn.li3.dev/@li3/\" } }\n <\/script>\n</head>\n<body class=\"bg-gray-950 text-gray-100 min-h-screen p-4 md:p-6 font-sans\">\n <template app>\n <main class=\"max-w-6xl mx-auto space-y-6\">\n <header class=\"flex flex-col sm:flex-row sm:items-center justify-between gap-3 border-b border-gray-800 pb-4\">\n <div>\n <h1 class=\"text-2xl font-bold text-white\">Runner Engine Status</h1>\n <p class=\"text-xs text-gray-400\">Live Job Queue & Execution Traces</p>\n </div>\n <div class=\"flex items-center gap-3 text-xs font-mono\">\n <span class=\"text-gray-500\">Updated {{ lastUpdated }}</span>\n <span\n class=\"px-3 py-1 rounded-full border\"\n bind-class=\"{\n 'bg-emerald-500/10.text-emerald-400.border-emerald-500/20': !refreshError,\n 'bg-rose-500/10.text-rose-400.border-rose-500/20': refreshError\n }\"\n >\n {{ refreshError ? 'Refresh failed' : 'System operational' }}\n </span>\n </div>\n </header>\n\n <section class=\"bg-gray-900 border border-gray-800 rounded-xl overflow-hidden hidden md:block\">\n <table class=\"w-full text-left text-sm\">\n <thead class=\"bg-gray-800/50 text-gray-400 text-xs uppercase font-mono border-b border-gray-800\">\n <tr>\n <th class=\"py-3 px-4\">Job ID</th>\n <th class=\"py-3 px-4\">Workflow</th>\n <th class=\"py-3 px-4\">Status</th>\n <th class=\"py-3 px-4 hidden xl:table-cell\">Worker</th>\n <th class=\"py-3 px-4 hidden lg:table-cell\">Created At</th>\n <th class=\"py-3 px-4 text-right\">Action</th>\n </tr>\n </thead>\n <tbody>\n <template for=\"job of jobs\">\n <tr class=\"border-b border-gray-800 hover:bg-gray-800/40 transition\">\n <td class=\"py-3 px-4 font-mono text-indigo-400\">\n <a attr-href=\"'/runs/' + job.id\" class=\"hover:underline\">#{{ job.id }}</a>\n </td>\n <td class=\"py-3 px-4 font-medium text-white\">{{ job.workflowId }}</td>\n <td class=\"py-3 px-4\">\n <span\n class=\"px-2.5 py-0.5 rounded-full text-xs font-semibold\"\n bind-class=\"{\n 'bg-emerald-500/10.text-emerald-400': job.status === 'success',\n 'bg-rose-500/10.text-rose-400': job.status === 'failed',\n 'bg-indigo-500/10.text-indigo-400.animate-pulse': job.status === 'running',\n 'bg-gray-500/10.text-gray-400': !['success', 'failed', 'running'].includes(job.status)\n }\"\n >\n {{ upper(job.status) }}\n </span>\n </td>\n <td class=\"py-3 px-4 hidden xl:table-cell text-xs font-mono text-gray-400\">{{ job.workerId || '-' }}</td>\n <td class=\"py-3 px-4 hidden lg:table-cell text-xs text-gray-400\">{{ job.createdAt }}</td>\n <td class=\"py-3 px-4 text-right whitespace-nowrap\">\n <a attr-href=\"'/runs/' + job.id\" class=\"text-xs bg-gray-800 hover:bg-gray-700 text-gray-200 px-3 py-1 rounded border border-gray-700\">View Trace</a>\n </td>\n </tr>\n </template>\n </tbody>\n </table>\n <template if=\"!jobs.length\">\n <div class=\"p-8 text-center text-gray-500\">No jobs recorded yet.</div>\n </template>\n </section>\n\n <section class=\"md:hidden bg-gray-900 border border-gray-800 rounded-xl divide-y divide-gray-800 overflow-hidden\">\n <template for=\"job of jobs\">\n <article class=\"p-4 bg-gray-900/60\">\n <div class=\"flex items-start justify-between gap-3\">\n <div class=\"min-w-0\">\n <div class=\"flex items-center gap-2\">\n <span\n class=\"w-2.5 h-2.5 rounded-full shrink-0\"\n bind-class=\"{\n 'bg-emerald-400': job.status === 'success',\n 'bg-rose-400': job.status === 'failed',\n 'bg-indigo-400.animate-pulse': job.status === 'running',\n 'bg-gray-500': !['success', 'failed', 'running'].includes(job.status)\n }\"\n ></span>\n <h2 class=\"font-medium text-white truncate\">{{ job.workflowId }}</h2>\n </div>\n <p class=\"mt-1 pl-[18px] text-xs font-mono text-gray-400\">#{{ job.id }} · {{ upper(job.status) }}</p>\n </div>\n <a attr-href=\"'/runs/' + job.id\" class=\"shrink-0 text-xs bg-gray-800 hover:bg-gray-700 text-gray-300 px-2.5 py-1 rounded border border-gray-700\">Trace</a>\n </div>\n </article>\n </template>\n <template if=\"!jobs.length\">\n <div class=\"p-8 text-center text-gray-500\">No jobs recorded yet.</div>\n </template>\n </section>\n\n <template if=\"hasMore\">\n <div class=\"flex justify-center\">\n <button\n class=\"px-4 py-2 text-sm text-gray-200 bg-gray-800 hover:bg-gray-700 border border-gray-700 rounded-lg\"\n on-click=\"loadMore()\"\n >\n {{ loadingMore ? 'Loading...' : 'Load more' }}\n </button>\n </div>\n </template>\n </main>\n\n <script setup>\n import { onDestroy, onInit, ref } from '@li3/web';\n\n export default function setup() {\n const jobs = ref([]);\n const lastUpdated = ref('now');\n const refreshError = ref(false);\n const hasMore = ref(false);\n const loadingMore = ref(false);\n let refreshTimer;\n let eventSource;\n let refreshing = false;\n let refreshPending = false;\n\n const upper = (value) => String(value || '').toUpperCase();\n const terminalStatuses = new Set(['success', 'failed', 'cancelled']);\n const refreshJobs = async () => {\n if (refreshing) {\n refreshPending = true;\n return;\n }\n refreshing = true;\n\n try {\n const activeIds = jobs.value\n .filter((job) => !terminalStatuses.has(job.status))\n .map((job) => Number(job.id));\n const knownIds = jobs.value.map((job) => Number(job.id));\n const afterId = activeIds.length\n ? Math.max(0, Math.min(...activeIds) - 1)\n : knownIds.length\n ? Math.max(...knownIds)\n : null;\n const url = afterId === null ? '/api/jobs?limit=500' : `/api/jobs?afterId=${afterId}&limit=500`;\n const response = await fetch(url, { headers: { accept: 'application/json' } });\n if (!response.ok) throw new Error(`Dashboard refresh failed: ${response.status}`);\n\n const data = await response.json();\n const merged = new Map(jobs.value.map((job) => [job.id, job]));\n for (const job of data.jobs) merged.set(job.id, job);\n jobs.value = Array.from(merged.values()).sort((a, b) => Number(b.id) - Number(a.id));\n lastUpdated.value = new Date().toLocaleTimeString();\n refreshError.value = false;\n } catch (error) {\n console.error(error);\n refreshError.value = true;\n } finally {\n refreshing = false;\n if (refreshPending) {\n refreshPending = false;\n void refreshJobs();\n }\n }\n };\n\n const loadMore = async () => {\n if (loadingMore.value || !hasMore.value || !jobs.value.length) return;\n loadingMore.value = true;\n\n try {\n const beforeId = Math.min(...jobs.value.map((job) => Number(job.id)));\n const response = await fetch(`/api/jobs?beforeId=${beforeId}`, {\n headers: { accept: 'application/json' },\n });\n if (!response.ok) throw new Error(`Loading older jobs failed: ${response.status}`);\n\n const data = await response.json();\n const merged = new Map(jobs.value.map((job) => [job.id, job]));\n for (const job of data.jobs) merged.set(job.id, job);\n jobs.value = Array.from(merged.values()).sort((a, b) => Number(b.id) - Number(a.id));\n hasMore.value = data.hasMore;\n } catch (error) {\n console.error(error);\n refreshError.value = true;\n } finally {\n loadingMore.value = false;\n }\n };\n\n onInit(() => {\n eventSource = new EventSource('/api/events');\n eventSource.addEventListener('jobs.available', refreshJobs);\n eventSource.addEventListener('jobs.changed', refreshJobs);\n eventSource.onerror = () => {\n refreshError.value = true;\n };\n refreshTimer = setInterval(refreshJobs, 60000);\n });\n onDestroy(() => {\n eventSource?.close();\n clearInterval(refreshTimer);\n });\n\n return { jobs, lastUpdated, refreshError, hasMore, loadingMore, loadMore, upper };\n }\n <\/script>\n <script state>__DASHBOARD_STATE__<\/script>\n </template>\n\n <script type=\"module\">import '@li3/web';<\/script>\n <script src=\"https://cdn.tailwindcss.com\"><\/script>\n</body>\n</html>\n";
|
|
8036
8042
|
//#endregion
|
|
8037
8043
|
//#region src/dashboard.ts
|
|
8038
8044
|
function zo(e) {
|
|
@@ -8052,20 +8058,77 @@ function Bo(e, t = !1) {
|
|
|
8052
8058
|
}));
|
|
8053
8059
|
}
|
|
8054
8060
|
//#endregion
|
|
8061
|
+
//#region src/events.ts
|
|
8062
|
+
var Vo = class {
|
|
8063
|
+
clients = /* @__PURE__ */ new Map();
|
|
8064
|
+
nextId = 1;
|
|
8065
|
+
maxClients = 1e3;
|
|
8066
|
+
subscribe(e, t) {
|
|
8067
|
+
if (this.clients.size >= this.maxClients) {
|
|
8068
|
+
t.writeHead(503, {
|
|
8069
|
+
"Content-Type": "application/json",
|
|
8070
|
+
"Retry-After": "5"
|
|
8071
|
+
}), t.end(JSON.stringify({ error: "Too many event stream clients" }));
|
|
8072
|
+
return;
|
|
8073
|
+
}
|
|
8074
|
+
t.writeHead(200, {
|
|
8075
|
+
"Cache-Control": "no-cache, no-transform",
|
|
8076
|
+
Connection: "keep-alive",
|
|
8077
|
+
"Content-Type": "text/event-stream",
|
|
8078
|
+
"X-Accel-Buffering": "no"
|
|
8079
|
+
}), t.write("retry: 2000\n\n");
|
|
8080
|
+
let n = setInterval(() => t.write(": heartbeat\n\n"), 3e4);
|
|
8081
|
+
n.unref(), this.clients.set(t, n), e.once("close", () => {
|
|
8082
|
+
clearInterval(n), this.clients.delete(t);
|
|
8083
|
+
});
|
|
8084
|
+
}
|
|
8085
|
+
publish(e, t = {}) {
|
|
8086
|
+
let n = `id: ${this.nextId++}\nevent: ${e}\ndata: ${JSON.stringify(t)}\n\n`;
|
|
8087
|
+
for (let [e, t] of this.clients) e.write(n) || (clearInterval(t), this.clients.delete(e), e.end());
|
|
8088
|
+
}
|
|
8089
|
+
close() {
|
|
8090
|
+
for (let [e, t] of this.clients) clearInterval(t), e.end();
|
|
8091
|
+
this.clients.clear();
|
|
8092
|
+
}
|
|
8093
|
+
};
|
|
8094
|
+
async function Ho(e, t, n, r) {
|
|
8095
|
+
let i = await fetch(new URL("/api/events", e), {
|
|
8096
|
+
headers: { Accept: "text/event-stream" },
|
|
8097
|
+
signal: t
|
|
8098
|
+
});
|
|
8099
|
+
if (!i.ok || !i.body) throw Error(`Event stream failed with HTTP ${i.status}`);
|
|
8100
|
+
r?.();
|
|
8101
|
+
let a = new TextDecoder(), o = "";
|
|
8102
|
+
for await (let e of i.body) {
|
|
8103
|
+
o += a.decode(e, { stream: !0 }).replaceAll("\r\n", "\n");
|
|
8104
|
+
let t = o.indexOf("\n\n");
|
|
8105
|
+
for (; t !== -1;) {
|
|
8106
|
+
let e = o.slice(0, t);
|
|
8107
|
+
o = o.slice(t + 2), t = o.indexOf("\n\n");
|
|
8108
|
+
let r = e.match(/^event: (.+)$/m)?.[1];
|
|
8109
|
+
if (!r) continue;
|
|
8110
|
+
let i = e.match(/^data: (.*)$/m)?.[1];
|
|
8111
|
+
n(r, i ? JSON.parse(i) : {});
|
|
8112
|
+
}
|
|
8113
|
+
}
|
|
8114
|
+
}
|
|
8115
|
+
//#endregion
|
|
8055
8116
|
//#region src/server.ts
|
|
8056
|
-
var
|
|
8117
|
+
var Uo = 50, Wo = 500, Go = class e {
|
|
8057
8118
|
server;
|
|
8058
8119
|
preprocessors = /* @__PURE__ */ new Map();
|
|
8059
8120
|
workflows = [];
|
|
8060
8121
|
queue;
|
|
8061
8122
|
secrets;
|
|
8062
8123
|
adminToken;
|
|
8124
|
+
events = new Vo();
|
|
8125
|
+
workflowsLoaded;
|
|
8063
8126
|
static async withPort(t) {
|
|
8064
8127
|
let { port: n, ...r } = t;
|
|
8065
8128
|
return new e(r).listen(n);
|
|
8066
8129
|
}
|
|
8067
8130
|
constructor(e) {
|
|
8068
|
-
this.queue = e.queue, this.secrets = e.secrets, this.adminToken = e.adminToken, Lo.from(e.config.workflows).then((t) => {
|
|
8131
|
+
this.queue = e.queue, this.secrets = e.secrets, this.adminToken = e.adminToken, this.workflowsLoaded = Lo.from(e.config.workflows).then((t) => {
|
|
8069
8132
|
this.workflows = t, console.log(`✅ Loaded ${t.length} workflow(s) from ${e.config.workflows}`);
|
|
8070
8133
|
}), this.registerPreprocessor(new Mo()), this.server = f.createServer((e, t) => this.handleRequest(e, t));
|
|
8071
8134
|
}
|
|
@@ -8076,9 +8139,11 @@ var Vo = 50, Ho = 500, Uo = class e {
|
|
|
8076
8139
|
let n = new p(e.url || "/", `${e.headers["x-forwarded-proto"] || "http"}://${e.headers["x-forwarded-host"] || e.headers.host}`);
|
|
8077
8140
|
if (e.method === "GET" && (n.pathname === "/runs" || n.pathname === "/")) return this.renderDashboard(t);
|
|
8078
8141
|
if (e.method === "GET" && n.pathname === "/api/jobs") {
|
|
8079
|
-
let e = n.searchParams.get("afterId"), r = n.searchParams.get("beforeId"), i = n.searchParams.get("limit"), a = e === null ? void 0 : Number(e), o = r === null ? void 0 : Number(r), s = i === null ?
|
|
8080
|
-
return a !== void 0 && (!Number.isSafeInteger(a) || a < 0) ? (t.writeHead(400, { "Content-Type": "application/json; charset=utf-8" }), t.end(JSON.stringify({ error: "afterId must be a non-negative integer" }))) : o !== void 0 && (!Number.isSafeInteger(o) || o < 1) ? (t.writeHead(400, { "Content-Type": "application/json; charset=utf-8" }), t.end(JSON.stringify({ error: "beforeId must be a positive integer" }))) : !Number.isSafeInteger(s) || s < 1 || s >
|
|
8142
|
+
let e = n.searchParams.get("afterId"), r = n.searchParams.get("beforeId"), i = n.searchParams.get("limit"), a = e === null ? void 0 : Number(e), o = r === null ? void 0 : Number(r), s = i === null ? Uo : Number(i);
|
|
8143
|
+
return a !== void 0 && (!Number.isSafeInteger(a) || a < 0) ? (t.writeHead(400, { "Content-Type": "application/json; charset=utf-8" }), t.end(JSON.stringify({ error: "afterId must be a non-negative integer" }))) : o !== void 0 && (!Number.isSafeInteger(o) || o < 1) ? (t.writeHead(400, { "Content-Type": "application/json; charset=utf-8" }), t.end(JSON.stringify({ error: "beforeId must be a positive integer" }))) : !Number.isSafeInteger(s) || s < 1 || s > Wo ? (t.writeHead(400, { "Content-Type": "application/json; charset=utf-8" }), t.end(JSON.stringify({ error: `limit must be an integer from 1 to ${Wo}` }))) : this.renderDashboardJobs(t, s, a, o);
|
|
8081
8144
|
}
|
|
8145
|
+
if (e.method === "GET" && n.pathname === "/api/events") return this.events.subscribe(e, t);
|
|
8146
|
+
if (e.method === "POST" && n.pathname === "/api/events") return this.handleWorkerEvent(e, t);
|
|
8082
8147
|
if (e.method === "GET" && n.pathname.startsWith("/runs/")) {
|
|
8083
8148
|
let e = n.pathname.replace("/runs/", "");
|
|
8084
8149
|
return this.renderRunDetails(e, t);
|
|
@@ -8103,7 +8168,7 @@ var Vo = 50, Ho = 500, Uo = class e {
|
|
|
8103
8168
|
n.writeHead(401, { "Content-Type": "application/json" }), n.end(JSON.stringify({ error: "Invalid HMAC signature or authentication failed" }));
|
|
8104
8169
|
return;
|
|
8105
8170
|
}
|
|
8106
|
-
this.matchWorkflows(e, o), n.writeHead(202, { "Content-Type": "application/json" }), n.end(JSON.stringify({ message: "OK" }));
|
|
8171
|
+
await this.workflowsLoaded, await this.matchWorkflows(e, o), n.writeHead(202, { "Content-Type": "application/json" }), n.end(JSON.stringify({ message: "OK" }));
|
|
8107
8172
|
} catch (e) {
|
|
8108
8173
|
console.error("❌ Webhook Ingress Error:", e), n.writeHead(500, { "Content-Type": "application/json" }), n.end(JSON.stringify({
|
|
8109
8174
|
error: "Internal Ingress Error",
|
|
@@ -8169,17 +8234,22 @@ var Vo = 50, Ho = 500, Uo = class e {
|
|
|
8169
8234
|
workflowId: n.id,
|
|
8170
8235
|
env: n.env,
|
|
8171
8236
|
steps: n.steps,
|
|
8172
|
-
inputs: t
|
|
8237
|
+
inputs: t,
|
|
8238
|
+
tags: n.tags
|
|
8173
8239
|
};
|
|
8174
|
-
await this.queue.enqueue(n.id, a, i);
|
|
8240
|
+
await this.queue.enqueue(n.id, a, i), this.events.publish("jobs.available", { tags: n.tags || [] });
|
|
8175
8241
|
}
|
|
8176
8242
|
}
|
|
8177
8243
|
async handleSecretReload(e, t) {
|
|
8178
8244
|
if (e.headers.authorization !== `Bearer ${this.adminToken}`) return t.writeHead(403, { "Content-Type": "application/json" }), t.end(JSON.stringify({ error: "Unauthorized" }));
|
|
8179
8245
|
this.secrets.reload(), console.log("🔄 SecretStore reloaded successfully without downtime!"), t.writeHead(200, { "Content-Type": "application/json" }), t.end(JSON.stringify({ message: "Secrets reloaded successfully" }));
|
|
8180
8246
|
}
|
|
8247
|
+
async handleWorkerEvent(e, t) {
|
|
8248
|
+
if (!this.adminToken || e.headers.authorization !== `Bearer ${this.adminToken}`) return t.writeHead(403, { "Content-Type": "application/json" }), t.end(JSON.stringify({ error: "Unauthorized" }));
|
|
8249
|
+
this.events.publish("jobs.changed"), t.writeHead(202).end();
|
|
8250
|
+
}
|
|
8181
8251
|
async renderDashboard(e) {
|
|
8182
|
-
let t = await this.queue.listJobs(51), n = zo(t.slice(0,
|
|
8252
|
+
let t = await this.queue.listJobs(51), n = zo(t.slice(0, Uo)), r = this.secrets.redactText(Bo(n, t.length > Uo));
|
|
8183
8253
|
e.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }), e.end(r);
|
|
8184
8254
|
}
|
|
8185
8255
|
async renderDashboardJobs(e, t, n, r) {
|
|
@@ -8234,7 +8304,7 @@ var Vo = 50, Ho = 500, Uo = class e {
|
|
|
8234
8304
|
async handleRestartJob(e, t) {
|
|
8235
8305
|
let n = await this.queue.restartJob(e);
|
|
8236
8306
|
if (n) {
|
|
8237
|
-
t.writeHead(201, { "Content-Type": "application/json" }), t.end(JSON.stringify({ id: n }));
|
|
8307
|
+
this.events.publish("jobs.available"), t.writeHead(201, { "Content-Type": "application/json" }), t.end(JSON.stringify({ id: n }));
|
|
8238
8308
|
return;
|
|
8239
8309
|
}
|
|
8240
8310
|
t.writeHead(404, { "Content-Type": "application/json" }), t.end(JSON.stringify({ error: "Job not found" }));
|
|
@@ -8247,13 +8317,13 @@ var Vo = 50, Ho = 500, Uo = class e {
|
|
|
8247
8317
|
});
|
|
8248
8318
|
}
|
|
8249
8319
|
async stop() {
|
|
8250
|
-
return new Promise((e) => {
|
|
8320
|
+
return this.events.close(), new Promise((e) => {
|
|
8251
8321
|
this.server.close(() => {
|
|
8252
8322
|
console.log("🌐 Webhook Ingress Server stopped listening."), e();
|
|
8253
8323
|
});
|
|
8254
8324
|
});
|
|
8255
8325
|
}
|
|
8256
|
-
},
|
|
8326
|
+
}, Ko = d(v), qo = class {
|
|
8257
8327
|
name = "systemd";
|
|
8258
8328
|
async isSupported() {
|
|
8259
8329
|
try {
|
|
@@ -8376,7 +8446,7 @@ var Vo = 50, Ho = 500, Uo = class e {
|
|
|
8376
8446
|
cancel: async () => {
|
|
8377
8447
|
d = !0;
|
|
8378
8448
|
try {
|
|
8379
|
-
t.image && await
|
|
8449
|
+
t.image && await Ko(`docker stop -t 2 ${o}`).catch(() => {}), await Ko(`systemctl stop ${o}.service`).catch(() => {});
|
|
8380
8450
|
} catch {}
|
|
8381
8451
|
},
|
|
8382
8452
|
logFilePath: i
|
|
@@ -8386,7 +8456,7 @@ var Vo = 50, Ho = 500, Uo = class e {
|
|
|
8386
8456
|
let t = await g(e, "utf-8"), n = t.includes("Running as unit: ") ? t.indexOf("\n") + 1 : 0, r = t.includes("Finished with result: ") ? t.lastIndexOf("Finished with result: ") : t.length;
|
|
8387
8457
|
return t.slice(n, r);
|
|
8388
8458
|
}
|
|
8389
|
-
},
|
|
8459
|
+
}, Jo = class {
|
|
8390
8460
|
name = "standard-process";
|
|
8391
8461
|
async isSupported() {
|
|
8392
8462
|
return !0;
|
|
@@ -8501,13 +8571,13 @@ var Vo = 50, Ho = 500, Uo = class e {
|
|
|
8501
8571
|
};
|
|
8502
8572
|
//#endregion
|
|
8503
8573
|
//#region src/drivers/index.ts
|
|
8504
|
-
async function
|
|
8505
|
-
let e = new
|
|
8506
|
-
return await e.isSupported() ? (console.log("⚡ Selected Execution Driver: Systemd (cgroups enabled)"), e) : (console.log("📦 Selected Execution Driver: Standard Process (Fallback)"), new
|
|
8574
|
+
async function Yo() {
|
|
8575
|
+
let e = new qo();
|
|
8576
|
+
return await e.isSupported() ? (console.log("⚡ Selected Execution Driver: Systemd (cgroups enabled)"), e) : (console.log("📦 Selected Execution Driver: Standard Process (Fallback)"), new Jo());
|
|
8507
8577
|
}
|
|
8508
8578
|
//#endregion
|
|
8509
8579
|
//#region src/signals.ts
|
|
8510
|
-
async function
|
|
8580
|
+
async function Xo(e) {
|
|
8511
8581
|
let t = !1;
|
|
8512
8582
|
async function n(n) {
|
|
8513
8583
|
if (!t) {
|
|
@@ -8515,7 +8585,7 @@ async function Jo(e) {
|
|
|
8515
8585
|
console.error("⚠️ Graceful shutdown timed out after 10s. Forcing exit!"), process.exit(1);
|
|
8516
8586
|
}, 1e4).unref();
|
|
8517
8587
|
try {
|
|
8518
|
-
|
|
8588
|
+
ns(), e.length > 0 && (console.log("⚙️ Waiting for active worker jobs to drain..."), await Promise.allSettled(e)), console.log("✨ Engine stopped cleanly. Goodbye!"), process.exit(0);
|
|
8519
8589
|
} catch (e) {
|
|
8520
8590
|
console.error("❌ Error during graceful shutdown:", e.message), process.exit(1);
|
|
8521
8591
|
}
|
|
@@ -8525,34 +8595,99 @@ async function Jo(e) {
|
|
|
8525
8595
|
}
|
|
8526
8596
|
//#endregion
|
|
8527
8597
|
//#region src/worker.ts
|
|
8528
|
-
var
|
|
8529
|
-
function
|
|
8530
|
-
|
|
8531
|
-
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
|
|
8538
|
-
|
|
8539
|
-
|
|
8540
|
-
|
|
8598
|
+
var Zo = !!process.env.DEBUG, Qo = { isStopping: !1 }, $o = /* @__PURE__ */ new Set(), es = null, ts = null;
|
|
8599
|
+
function ns() {
|
|
8600
|
+
Qo.isStopping = !0, es?.abort(), ts?.();
|
|
8601
|
+
}
|
|
8602
|
+
function rs(e, t, n, r) {
|
|
8603
|
+
Qo.isStopping = !1;
|
|
8604
|
+
let i = [is(e, t, n, r)];
|
|
8605
|
+
return Xo(i), i;
|
|
8606
|
+
}
|
|
8607
|
+
async function is(e, t, n, r) {
|
|
8608
|
+
let i = await Yo(), a = /* @__PURE__ */ new Set(), o = 0, s = null, c = () => {
|
|
8609
|
+
o++, s?.();
|
|
8610
|
+
};
|
|
8611
|
+
ts = c, es = new AbortController();
|
|
8612
|
+
let l = as(r, es.signal, c);
|
|
8613
|
+
for (console.log(`🚀 Worker scheduler started. Driver: ${i.name}. Concurrency: ${e}. Tags: ${r.tags.join(", ") || "(none)"}`); !Qo.isStopping;) {
|
|
8614
|
+
let l = o;
|
|
8615
|
+
try {
|
|
8616
|
+
for (; a.size < e && !Qo.isStopping;) {
|
|
8617
|
+
let e = await t.claimNextJob(r.tags);
|
|
8618
|
+
if (!e) break;
|
|
8619
|
+
if (Qo.isStopping) {
|
|
8620
|
+
await t.releaseJob(e.id);
|
|
8621
|
+
break;
|
|
8622
|
+
}
|
|
8623
|
+
let o = `worker-${e.id}`, s;
|
|
8624
|
+
s = (async () => {
|
|
8625
|
+
cs(r), await ls({
|
|
8626
|
+
workerId: o,
|
|
8627
|
+
job: e,
|
|
8628
|
+
queue: t,
|
|
8629
|
+
secrets: n,
|
|
8630
|
+
config: r,
|
|
8631
|
+
driver: i
|
|
8632
|
+
});
|
|
8633
|
+
})().catch((e) => console.error(`[${o}] ⚠️ Worker execution error:`, e)).finally(() => {
|
|
8634
|
+
a.delete(s), cs(r), c();
|
|
8635
|
+
}), a.add(s);
|
|
8636
|
+
}
|
|
8637
|
+
} catch (e) {
|
|
8638
|
+
console.error("⚠️ Worker scheduler claim error:", e), setTimeout(c, 5e3).unref();
|
|
8639
|
+
}
|
|
8640
|
+
!Qo.isStopping && o === l && (await os(l, () => o, (e) => s = e), s = null);
|
|
8641
|
+
}
|
|
8642
|
+
es.abort(), await Promise.allSettled(a), await l, ts = null, console.log("🛑 Worker scheduler stopped cleanly.");
|
|
8643
|
+
}
|
|
8644
|
+
async function as(e, t, n) {
|
|
8645
|
+
let r = 1e3;
|
|
8646
|
+
for (; !t.aborted;) {
|
|
8647
|
+
try {
|
|
8648
|
+
await Ho(e.serverUrl, t, (t, r) => {
|
|
8649
|
+
t === "jobs.available" && (Array.isArray(r.tags) ? r.tags.filter((e) => typeof e == "string") : []).every((t) => e.tags.includes(t)) && n();
|
|
8650
|
+
}, n), r = 1e3;
|
|
8651
|
+
} catch (e) {
|
|
8652
|
+
if (t.aborted || e?.name === "AbortError") break;
|
|
8653
|
+
console.error(`⚠️ Worker event stream disconnected: ${e.message}`);
|
|
8541
8654
|
}
|
|
8542
|
-
await
|
|
8543
|
-
|
|
8544
|
-
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
|
|
8548
|
-
|
|
8655
|
+
await ss(r, t), r = Math.min(r * 2, 3e4);
|
|
8656
|
+
}
|
|
8657
|
+
}
|
|
8658
|
+
function os(e, t, n) {
|
|
8659
|
+
return new Promise((r) => {
|
|
8660
|
+
if (t() !== e) return r();
|
|
8661
|
+
let i = setTimeout(r, 6e4);
|
|
8662
|
+
n(() => {
|
|
8663
|
+
clearTimeout(i), r();
|
|
8549
8664
|
});
|
|
8550
|
-
}
|
|
8551
|
-
|
|
8665
|
+
});
|
|
8666
|
+
}
|
|
8667
|
+
function ss(e, t) {
|
|
8668
|
+
return new Promise((n) => {
|
|
8669
|
+
if (t.aborted) return n();
|
|
8670
|
+
let r = () => {
|
|
8671
|
+
clearTimeout(i), n();
|
|
8672
|
+
}, i = setTimeout(() => {
|
|
8673
|
+
t.removeEventListener("abort", r), n();
|
|
8674
|
+
}, e);
|
|
8675
|
+
t.addEventListener("abort", r, { once: !0 });
|
|
8676
|
+
});
|
|
8677
|
+
}
|
|
8678
|
+
async function cs(e) {
|
|
8679
|
+
if (e.adminToken) try {
|
|
8680
|
+
let t = await fetch(new URL("/api/events", e.serverUrl), {
|
|
8681
|
+
method: "POST",
|
|
8682
|
+
headers: { Authorization: `Bearer ${e.adminToken}` },
|
|
8683
|
+
signal: AbortSignal.timeout(5e3)
|
|
8684
|
+
});
|
|
8685
|
+
!t.ok && Zo && console.error(`Failed to publish job status event: HTTP ${t.status}`);
|
|
8686
|
+
} catch (e) {
|
|
8687
|
+
Zo && console.error("Failed to publish job status event:", e);
|
|
8552
8688
|
}
|
|
8553
|
-
console.log(`[${e}] 🛑 Worker loop stopped cleanly.`);
|
|
8554
8689
|
}
|
|
8555
|
-
async function
|
|
8690
|
+
async function ls(e) {
|
|
8556
8691
|
let { workerId: t, job: n, config: r, secrets: i, queue: o } = e;
|
|
8557
8692
|
console.log(`\n[${t}] 📦 Claimed Job #${n.id} (Workflow: ${n.workflow_id})`);
|
|
8558
8693
|
let s = typeof n.payload == "string" ? JSON.parse(n.payload) : n.payload, c = s.steps || [], l = s.inputs || {}, u = Date.now(), d = a.join(r.storagePath, `job-${n.id}`), f = a.join(d, "logs"), p = a.join(d, "wd"), m = {
|
|
@@ -8569,20 +8704,20 @@ async function $o(e) {
|
|
|
8569
8704
|
durationMs: 0,
|
|
8570
8705
|
outputs: {},
|
|
8571
8706
|
logContent: ""
|
|
8572
|
-
})), g =
|
|
8707
|
+
})), g = gs(n, "running", u, l, m.env, h, s);
|
|
8573
8708
|
await o.saveReport(n.id, g);
|
|
8574
|
-
let { cancelled: _, failed: v } = await
|
|
8709
|
+
let { cancelled: _, failed: v } = await us({
|
|
8575
8710
|
payload: s,
|
|
8576
8711
|
steps: c,
|
|
8577
8712
|
executionContext: m,
|
|
8578
8713
|
...e
|
|
8579
8714
|
}, g), y = _ ? "cancelled" : v ? "failed" : "success";
|
|
8580
|
-
g.status = y, g.durationMs = Date.now() - u, g.finishedAt = (/* @__PURE__ */ new Date()).toISOString(), await o.completeJob(n.id, y, g), console.log(`[${t}] ✅ Job #${n.id} completed as: ${y}`), await
|
|
8715
|
+
g.status = y, g.durationMs = Date.now() - u, g.finishedAt = (/* @__PURE__ */ new Date()).toISOString(), await o.completeJob(n.id, y, g), console.log(`[${t}] ✅ Job #${n.id} completed as: ${y}`), await _s(t, r.reporters, g);
|
|
8581
8716
|
}
|
|
8582
|
-
async function
|
|
8717
|
+
async function us(e, t) {
|
|
8583
8718
|
let { driver: n, workerId: r, queue: i, config: a, job: o, payload: s, steps: c, executionContext: l } = e, u = t.steps, d = !1, f = !1, p = 0;
|
|
8584
8719
|
try {
|
|
8585
|
-
s.env && Object.assign(l.env, await
|
|
8720
|
+
s.env && Object.assign(l.env, await ps(s.env, l));
|
|
8586
8721
|
for (let e = 0; e < c.length; e++) {
|
|
8587
8722
|
let s = c[e], m = (/* @__PURE__ */ new Date()).toISOString();
|
|
8588
8723
|
u[e] = {
|
|
@@ -8596,7 +8731,7 @@ async function es(e, t) {
|
|
|
8596
8731
|
startedAt: m,
|
|
8597
8732
|
finishedAt: void 0
|
|
8598
8733
|
}, t.durationMs = Date.now() - Date.parse(t.startedAt), await i.saveReport(o.id, t);
|
|
8599
|
-
let h = await
|
|
8734
|
+
let h = await ds({
|
|
8600
8735
|
workerId: r,
|
|
8601
8736
|
jobId: o.id,
|
|
8602
8737
|
step: s,
|
|
@@ -8636,22 +8771,22 @@ async function es(e, t) {
|
|
|
8636
8771
|
} catch (e) {
|
|
8637
8772
|
console.log("🛑 Step failed", e), d = !0;
|
|
8638
8773
|
}
|
|
8639
|
-
return p < c.length && (
|
|
8774
|
+
return p < c.length && (hs(c, p, u), t.durationMs = Date.now() - Date.parse(t.startedAt), await i.saveReport(o.id, t)), {
|
|
8640
8775
|
failed: d,
|
|
8641
8776
|
cancelled: f,
|
|
8642
8777
|
stepReports: u
|
|
8643
8778
|
};
|
|
8644
8779
|
}
|
|
8645
|
-
async function
|
|
8780
|
+
async function ds(e) {
|
|
8646
8781
|
let { step: t, stepIndex: n, executionContext: r } = e;
|
|
8647
|
-
if (t.id ||= `step-${n}`, t.name ||= t.id, t.if && !await ko.evaluateConditions(t.if, r)) return
|
|
8782
|
+
if (t.id ||= `step-${n}`, t.name ||= t.id, t.if && !await ko.evaluateConditions(t.if, r)) return Zo && console.log(`⏩ Skipped step ${t.id} based on condition: ${t.if}`, r), {
|
|
8648
8783
|
failed: !1,
|
|
8649
8784
|
cancelled: !1,
|
|
8650
8785
|
skipped: !0,
|
|
8651
8786
|
report: null
|
|
8652
8787
|
};
|
|
8653
8788
|
try {
|
|
8654
|
-
let n = await
|
|
8789
|
+
let n = await ps(t.env, r), i = {
|
|
8655
8790
|
jobId: String(e.jobId),
|
|
8656
8791
|
step: t,
|
|
8657
8792
|
command: t.run,
|
|
@@ -8665,15 +8800,15 @@ async function ts(e) {
|
|
|
8665
8800
|
WORKING_DIR: r.workingDir
|
|
8666
8801
|
}
|
|
8667
8802
|
};
|
|
8668
|
-
return t.eval ?
|
|
8803
|
+
return t.eval ? fs({
|
|
8669
8804
|
...e,
|
|
8670
8805
|
stepContext: i
|
|
8671
|
-
}) :
|
|
8806
|
+
}) : ms({
|
|
8672
8807
|
...e,
|
|
8673
8808
|
stepContext: i
|
|
8674
8809
|
});
|
|
8675
8810
|
} catch (e) {
|
|
8676
|
-
return
|
|
8811
|
+
return Zo && console.error(`⏩ Failed to run step ${t.id}`, r, e), {
|
|
8677
8812
|
failed: !0,
|
|
8678
8813
|
cancelled: !1,
|
|
8679
8814
|
skipped: !1,
|
|
@@ -8681,7 +8816,7 @@ async function ts(e) {
|
|
|
8681
8816
|
};
|
|
8682
8817
|
}
|
|
8683
8818
|
}
|
|
8684
|
-
async function
|
|
8819
|
+
async function fs(e) {
|
|
8685
8820
|
let { queue: t, stepContext: n, executionContext: r } = e, { jobId: i, step: a } = n, o = Date.now(), s = a.id, c = a.name;
|
|
8686
8821
|
try {
|
|
8687
8822
|
let e = await ko.evaluateExpression(a.eval, r);
|
|
@@ -8727,12 +8862,12 @@ async function ns(e) {
|
|
|
8727
8862
|
};
|
|
8728
8863
|
}
|
|
8729
8864
|
}
|
|
8730
|
-
async function
|
|
8865
|
+
async function ps(e, t) {
|
|
8731
8866
|
let n = {};
|
|
8732
8867
|
if (e) for (let [r, i] of Object.entries(e)) n[r] = String(await ko.evaluateValue(i, t));
|
|
8733
8868
|
return n;
|
|
8734
8869
|
}
|
|
8735
|
-
async function
|
|
8870
|
+
async function ms(t) {
|
|
8736
8871
|
let { workerId: n, jobId: r, stepContext: i, executionContext: a, driver: o, queue: s } = t, { step: c } = i, l = c.id, u = c.name, d;
|
|
8737
8872
|
try {
|
|
8738
8873
|
d = o.execute(i);
|
|
@@ -8747,10 +8882,11 @@ async function is(t) {
|
|
|
8747
8882
|
logFilePath: ""
|
|
8748
8883
|
};
|
|
8749
8884
|
}
|
|
8885
|
+
$o.add(d);
|
|
8750
8886
|
let f = !1, p = setInterval(async () => {
|
|
8751
8887
|
await s.isCancelled(r) && (console.log(`[${n}] 🛑 Job #${r} was cancelled! Halting execution.`), f = !0, clearInterval(p), await d.cancel());
|
|
8752
8888
|
}, 3e3), m = await d.done;
|
|
8753
|
-
if (clearInterval(p), d.logFilePath && e.existsSync(d.logFilePath)) try {
|
|
8889
|
+
if (clearInterval(p), $o.delete(d), d.logFilePath && e.existsSync(d.logFilePath)) try {
|
|
8754
8890
|
let e = await o.readLog(d.logFilePath);
|
|
8755
8891
|
await s.saveStepLog(r, l, e);
|
|
8756
8892
|
} catch (e) {
|
|
@@ -8777,7 +8913,7 @@ async function is(t) {
|
|
|
8777
8913
|
}
|
|
8778
8914
|
};
|
|
8779
8915
|
}
|
|
8780
|
-
function
|
|
8916
|
+
function hs(e, t, n) {
|
|
8781
8917
|
for (let r = t; r < e.length; r++) {
|
|
8782
8918
|
let t = e[r], i = t.id || `step-${r}`;
|
|
8783
8919
|
n[r] = {
|
|
@@ -8791,7 +8927,7 @@ function as(e, t, n) {
|
|
|
8791
8927
|
};
|
|
8792
8928
|
}
|
|
8793
8929
|
}
|
|
8794
|
-
function
|
|
8930
|
+
function gs(e, t, n, r, i, a, o) {
|
|
8795
8931
|
return {
|
|
8796
8932
|
jobId: String(e.id),
|
|
8797
8933
|
parentId: String(e.parentId || ""),
|
|
@@ -8810,7 +8946,7 @@ function os(e, t, n, r, i, a, o) {
|
|
|
8810
8946
|
})
|
|
8811
8947
|
};
|
|
8812
8948
|
}
|
|
8813
|
-
async function
|
|
8949
|
+
async function _s(e, t = [], n) {
|
|
8814
8950
|
!Array.isArray(t) || t.length === 0 || (console.log(`[${e}] 📢 Dispatching execution report to ${t.length} reporter(s)...`), await Promise.allSettled(t.map(async (t) => {
|
|
8815
8951
|
try {
|
|
8816
8952
|
await t.report(n);
|
|
@@ -8821,7 +8957,7 @@ async function ss(e, t = [], n) {
|
|
|
8821
8957
|
}
|
|
8822
8958
|
//#endregion
|
|
8823
8959
|
//#region src/reporters/json-file.reporter.ts
|
|
8824
|
-
var
|
|
8960
|
+
var vs = class {
|
|
8825
8961
|
name = "json-file";
|
|
8826
8962
|
outputDir;
|
|
8827
8963
|
constructor(e) {
|
|
@@ -8832,7 +8968,7 @@ var cs = class {
|
|
|
8832
8968
|
let n = a.join(this.outputDir, `run-${t.jobId}.json`);
|
|
8833
8969
|
e.writeFileSync(n, JSON.stringify(t, null, 2), "utf-8"), console.log(`📊 Execution report saved to: ${n}`);
|
|
8834
8970
|
}
|
|
8835
|
-
},
|
|
8971
|
+
}, ys = class {
|
|
8836
8972
|
name = "slack";
|
|
8837
8973
|
webhookUrl = "";
|
|
8838
8974
|
token = "";
|
|
@@ -8859,7 +8995,7 @@ var cs = class {
|
|
|
8859
8995
|
};
|
|
8860
8996
|
//#endregion
|
|
8861
8997
|
//#region src/index.ts
|
|
8862
|
-
function
|
|
8998
|
+
function bs(e) {
|
|
8863
8999
|
console.log("🔍 Validating Workflows in:", e.workflows);
|
|
8864
9000
|
let t = new di(e.workflows), n = r(e.workflows).filter((e) => e.endsWith(".yml") || e.endsWith(".yaml"));
|
|
8865
9001
|
for (let e of n) {
|
|
@@ -8867,13 +9003,13 @@ function us(e) {
|
|
|
8867
9003
|
console.log(` ✅ ${e} -> Valid! (${n.length} job matrix variant(s) generated)`);
|
|
8868
9004
|
}
|
|
8869
9005
|
}
|
|
8870
|
-
async function
|
|
9006
|
+
async function xs() {
|
|
8871
9007
|
let { config: e, command: t } = await fe();
|
|
8872
|
-
if (e || process.exit(1), t === "validate") return
|
|
9008
|
+
if (e || process.exit(1), t === "validate") return bs(e);
|
|
8873
9009
|
let n = new mi("./.env"), r = new pi(process.env.WORKER_NAME || "cli");
|
|
8874
9010
|
switch (t) {
|
|
8875
9011
|
case "start-server":
|
|
8876
|
-
console.log("🌐 Starting Ingress Gateway..."), await r.init(), await
|
|
9012
|
+
console.log("🌐 Starting Ingress Gateway..."), await r.init(), await Go.withPort({
|
|
8877
9013
|
config: e,
|
|
8878
9014
|
queue: r,
|
|
8879
9015
|
secrets: n,
|
|
@@ -8882,11 +9018,11 @@ async function ds() {
|
|
|
8882
9018
|
});
|
|
8883
9019
|
break;
|
|
8884
9020
|
case "start-workers":
|
|
8885
|
-
console.log(`⚙️ Starting ${e.workers}
|
|
9021
|
+
console.log(`⚙️ Starting worker scheduler with ${e.workers} concurrent slot(s)...`), await r.init(), rs(e.workers, r, n, e);
|
|
8886
9022
|
break;
|
|
8887
9023
|
default: console.error(`❌ Unknown command: '${t}'`), de(), process.exit(1);
|
|
8888
9024
|
}
|
|
8889
9025
|
}
|
|
8890
|
-
|
|
9026
|
+
xs().catch(console.error);
|
|
8891
9027
|
//#endregion
|
|
8892
|
-
export { Io as HtmlReporter,
|
|
9028
|
+
export { Io as HtmlReporter, vs as JsonFileReporter, ys as SlackReporter };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml-loader.d.ts","sourceRoot":"","sources":["../../src/parser/yaml-loader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,qBAAa,UAAU;WACR,IAAI,CAAC,IAAI,EAAE,MAAM;IAiB9B,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,uBAAuB;
|
|
1
|
+
{"version":3,"file":"yaml-loader.d.ts","sourceRoot":"","sources":["../../src/parser/yaml-loader.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGjD,qBAAa,UAAU;WACR,IAAI,CAAC,IAAI,EAAE,MAAM;IAiB9B,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,uBAAuB;CAwChE"}
|
package/dist/queue.d.ts
CHANGED
|
@@ -9,10 +9,11 @@ export declare class QueueManager {
|
|
|
9
9
|
*/
|
|
10
10
|
enqueue(workflowId: string, payload: JobPayload, concurrencyKey?: string): Promise<any>;
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* Atomically claims the oldest pending job compatible with this worker.
|
|
13
13
|
* Requires SQLite >= 3.35 for the RETURNING clause.
|
|
14
14
|
*/
|
|
15
|
-
claimNextJob(): Promise<JobRecord | null>;
|
|
15
|
+
claimNextJob(workerTags?: string[]): Promise<JobRecord | null>;
|
|
16
|
+
releaseJob(jobId: string | number): Promise<void>;
|
|
16
17
|
/**
|
|
17
18
|
* Marks a job as completed or failed
|
|
18
19
|
*/
|
package/dist/queue.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvF,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,MAAM;IAE9B,IAAI;IAKV;;;OAGG;IACG,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,MAAM;IAkB9E;;;OAGG;IACG,YAAY,
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvF,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ;gBAAR,QAAQ,EAAE,MAAM;IAE9B,IAAI;IAKV;;;OAGG;IACG,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,MAAM;IAkB9E;;;OAGG;IACG,YAAY,CAAC,UAAU,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IA6BlE,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvD;;OAEG;IACG,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,SAAS;IAInD,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAStG,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAiBvC;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKrD,cAAc;IAMd,YAAY;IAoClB;;OAEG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAIlD;;OAEG;IACG,QAAQ,CAAC,KAAK,SAAK,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAiB/E;;OAEG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxF,2DAA2D;IACrD,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAU5F;;OAEG;IACG,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAS1E"}
|
package/dist/server.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export declare class WebhookServer {
|
|
|
6
6
|
private queue;
|
|
7
7
|
private secrets;
|
|
8
8
|
private adminToken;
|
|
9
|
+
private events;
|
|
10
|
+
private workflowsLoaded;
|
|
9
11
|
static withPort(options: WebhookServerOptions & {
|
|
10
12
|
port: number;
|
|
11
13
|
}): Promise<WebhookServer>;
|
|
@@ -23,6 +25,7 @@ export declare class WebhookServer {
|
|
|
23
25
|
* Handles Zero-Downtime Secret Reload
|
|
24
26
|
*/
|
|
25
27
|
private handleSecretReload;
|
|
28
|
+
private handleWorkerEvent;
|
|
26
29
|
/**
|
|
27
30
|
* Serves the Server Health & Jobs Dashboard
|
|
28
31
|
*/
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,mBAAmB,EACnB,oBAAoB,EAGrB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,mBAAmB,EACnB,oBAAoB,EAGrB,MAAM,YAAY,CAAC;AAQpB,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,aAAa,CAA0C;IAC/D,OAAO,CAAC,SAAS,CAA4B;IAC7C,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,eAAe,CAAgB;WAE1B,QAAQ,CAAC,OAAO,EAAE,oBAAoB,GAAG;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;gBAK1D,OAAO,EAAE,oBAAoB;IAczC,oBAAoB,CAAC,YAAY,EAAE,mBAAmB;YAIxC,aAAa;IAkE3B;;OAEG;YACW,aAAa;YA0Bb,WAAW;IAwBzB,OAAO,CAAC,UAAU;YAiBJ,cAAc;IA2C5B;;OAEG;YACW,kBAAkB;YAelB,iBAAiB;IAU/B;;OAEG;YACW,eAAe;YAQf,mBAAmB;IAWjC;;OAEG;YACW,gBAAgB;IAkC9B,OAAO,CAAC,kBAAkB;YA0BZ,gBAAgB;IAc9B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAStC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAS5B"}
|
package/dist/types.d.ts
CHANGED
|
@@ -15,6 +15,10 @@ export interface RunnerConfig {
|
|
|
15
15
|
workflows: string;
|
|
16
16
|
/** Number of concurrent worker loops to spawn */
|
|
17
17
|
workers: number;
|
|
18
|
+
/** Webhook server URL used for worker event notifications */
|
|
19
|
+
serverUrl: string;
|
|
20
|
+
/** Capabilities advertised by this worker node */
|
|
21
|
+
tags: string[];
|
|
18
22
|
/** Storage path for job workspaces and step logs */
|
|
19
23
|
storagePath: string;
|
|
20
24
|
/** Global environment variables injected into all step runs */
|
|
@@ -105,6 +109,8 @@ export interface WorkflowDefinition {
|
|
|
105
109
|
};
|
|
106
110
|
steps: WorkflowStep[];
|
|
107
111
|
env?: Record<string, string>;
|
|
112
|
+
/** Worker capabilities required to execute this workflow */
|
|
113
|
+
tags?: string[];
|
|
108
114
|
}
|
|
109
115
|
export interface WebhookServerOptions {
|
|
110
116
|
config: RunnerConfig;
|
|
@@ -129,6 +135,7 @@ export interface JobPayload {
|
|
|
129
135
|
steps: WorkflowStep[];
|
|
130
136
|
inputs: WorkflowInputs;
|
|
131
137
|
env?: Record<string, string>;
|
|
138
|
+
tags?: string[];
|
|
132
139
|
}
|
|
133
140
|
export interface MatrixStrategy {
|
|
134
141
|
matrix?: Record<string, (string | number | boolean)[]>;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/worker.d.ts
CHANGED
|
@@ -8,14 +8,15 @@ export declare const shutdownState: {
|
|
|
8
8
|
* Called by signal handlers in index.ts during graceful shutdown
|
|
9
9
|
*/
|
|
10
10
|
export declare function abortActiveWorkerTask(): Promise<void>;
|
|
11
|
+
export declare function requestWorkerShutdown(): void;
|
|
11
12
|
/**
|
|
12
13
|
* Spawns worker loops as requested by configuration
|
|
13
14
|
*/
|
|
14
15
|
export declare function startWorkers(count: number, queue: QueueManager, secrets: SecretStore, config: RunnerConfig): Promise<void>[];
|
|
15
16
|
/**
|
|
16
|
-
*
|
|
17
|
+
* Event-driven worker scheduler with bounded local concurrency.
|
|
17
18
|
*/
|
|
18
|
-
export declare function
|
|
19
|
+
export declare function startWorkerScheduler(concurrency: number, queue: QueueManager, secrets: SecretStore, config: RunnerConfig): Promise<void>;
|
|
19
20
|
/**
|
|
20
21
|
* Processes a single job sequentially
|
|
21
22
|
*/
|
package/dist/worker.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAGL,YAAY,EAOZ,WAAW,EAIZ,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAGL,YAAY,EAOZ,WAAW,EAIZ,MAAM,YAAY,CAAC;AAMpB,eAAO,MAAM,aAAa;;CAEzB,CAAC;AAMF;;GAEG;AACH,wBAAsB,qBAAqB,kBAK1C;AAED,wBAAgB,qBAAqB,SAIpC;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,mBAK1G;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,YAAY,EACnB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,YAAY,iBA4DrB;AA4ED;;GAEG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAAE,WAAW,iBA2D9C"}
|