adispatchd 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +195 -2
- package/dist/api/errors.d.ts +27 -0
- package/dist/api/errors.js +80 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/index.d.ts +10 -0
- package/dist/api/index.js +11 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/logs.d.ts +30 -0
- package/dist/api/logs.js +88 -0
- package/dist/api/logs.js.map +1 -0
- package/dist/api/serialize.d.ts +65 -0
- package/dist/api/serialize.js +135 -0
- package/dist/api/serialize.js.map +1 -0
- package/dist/api/server.d.ts +89 -0
- package/dist/api/server.js +751 -0
- package/dist/api/server.js.map +1 -0
- package/dist/api/sse.d.ts +90 -0
- package/dist/api/sse.js +225 -0
- package/dist/api/sse.js.map +1 -0
- package/dist/app.d.ts +173 -0
- package/dist/app.js +488 -0
- package/dist/app.js.map +1 -0
- package/dist/cli/config-validate.d.ts +6 -0
- package/dist/cli/config-validate.js +39 -0
- package/dist/cli/config-validate.js.map +1 -0
- package/dist/cli/control.d.ts +31 -0
- package/dist/cli/control.js +186 -0
- package/dist/cli/control.js.map +1 -0
- package/dist/cli/http-client.d.ts +57 -0
- package/dist/cli/http-client.js +174 -0
- package/dist/cli/http-client.js.map +1 -0
- package/dist/cli/index.d.ts +14 -0
- package/dist/cli/index.js +14 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init-templates.d.ts +20 -0
- package/dist/cli/init-templates.js +275 -0
- package/dist/cli/init-templates.js.map +1 -0
- package/dist/cli/init.d.ts +16 -0
- package/dist/cli/init.js +107 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +25 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/program.d.ts +102 -0
- package/dist/cli/program.js +133 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/service.d.ts +27 -0
- package/dist/cli/service.js +252 -0
- package/dist/cli/service.js.map +1 -0
- package/dist/cli/start.d.ts +22 -0
- package/dist/cli/start.js +133 -0
- package/dist/cli/start.js.map +1 -0
- package/dist/cli/workflow-dry-run.d.ts +13 -0
- package/dist/cli/workflow-dry-run.js +144 -0
- package/dist/cli/workflow-dry-run.js.map +1 -0
- package/dist/config/field-catalog.d.ts +33 -0
- package/dist/config/field-catalog.js +172 -0
- package/dist/config/field-catalog.js.map +1 -0
- package/dist/config/filter-schema.d.ts +15 -0
- package/dist/config/filter-schema.js +110 -0
- package/dist/config/filter-schema.js.map +1 -0
- package/dist/config/index.d.ts +15 -0
- package/dist/config/index.js +16 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/issues.d.ts +27 -0
- package/dist/config/issues.js +37 -0
- package/dist/config/issues.js.map +1 -0
- package/dist/config/loader.d.ts +32 -0
- package/dist/config/loader.js +250 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/manager.d.ts +153 -0
- package/dist/config/manager.js +276 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/config/model.d.ts +334 -0
- package/dist/config/model.js +2 -0
- package/dist/config/model.js.map +1 -0
- package/dist/config/normalize.d.ts +20 -0
- package/dist/config/normalize.js +200 -0
- package/dist/config/normalize.js.map +1 -0
- package/dist/config/parameters.d.ts +37 -0
- package/dist/config/parameters.js +71 -0
- package/dist/config/parameters.js.map +1 -0
- package/dist/config/public.d.ts +6 -0
- package/dist/config/public.js +18 -0
- package/dist/config/public.js.map +1 -0
- package/dist/config/schemas.d.ts +538 -0
- package/dist/config/schemas.js +321 -0
- package/dist/config/schemas.js.map +1 -0
- package/dist/config/snapshot.d.ts +38 -0
- package/dist/config/snapshot.js +57 -0
- package/dist/config/snapshot.js.map +1 -0
- package/dist/config/validate.d.ts +33 -0
- package/dist/config/validate.js +346 -0
- package/dist/config/validate.js.map +1 -0
- package/dist/core/clock.d.ts +59 -0
- package/dist/core/clock.js +133 -0
- package/dist/core/clock.js.map +1 -0
- package/dist/core/duration.d.ts +19 -0
- package/dist/core/duration.js +93 -0
- package/dist/core/duration.js.map +1 -0
- package/dist/core/errors.d.ts +62 -0
- package/dist/core/errors.js +72 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/ids.d.ts +57 -0
- package/dist/core/ids.js +88 -0
- package/dist/core/ids.js.map +1 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.js +14 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logger.d.ts +100 -0
- package/dist/core/logger.js +207 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/paths.d.ts +84 -0
- package/dist/core/paths.js +138 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/template.d.ts +136 -0
- package/dist/core/template.js +261 -0
- package/dist/core/template.js.map +1 -0
- package/dist/core/types.d.ts +544 -0
- package/dist/core/types.js +172 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/worker-protocol.d.ts +102 -0
- package/dist/core/worker-protocol.js +75 -0
- package/dist/core/worker-protocol.js.map +1 -0
- package/dist/executors/classify.d.ts +25 -0
- package/dist/executors/classify.js +54 -0
- package/dist/executors/classify.js.map +1 -0
- package/dist/executors/dispatcher.d.ts +35 -0
- package/dist/executors/dispatcher.js +68 -0
- package/dist/executors/dispatcher.js.map +1 -0
- package/dist/executors/env.d.ts +43 -0
- package/dist/executors/env.js +66 -0
- package/dist/executors/env.js.map +1 -0
- package/dist/executors/event-parser.d.ts +41 -0
- package/dist/executors/event-parser.js +106 -0
- package/dist/executors/event-parser.js.map +1 -0
- package/dist/executors/index.d.ts +12 -0
- package/dist/executors/index.js +13 -0
- package/dist/executors/index.js.map +1 -0
- package/dist/executors/log-capture.d.ts +57 -0
- package/dist/executors/log-capture.js +155 -0
- package/dist/executors/log-capture.js.map +1 -0
- package/dist/executors/process-identity.d.ts +124 -0
- package/dist/executors/process-identity.js +283 -0
- package/dist/executors/process-identity.js.map +1 -0
- package/dist/executors/shell-executor.d.ts +35 -0
- package/dist/executors/shell-executor.js +478 -0
- package/dist/executors/shell-executor.js.map +1 -0
- package/dist/executors/stream-redactor.d.ts +40 -0
- package/dist/executors/stream-redactor.js +89 -0
- package/dist/executors/stream-redactor.js.map +1 -0
- package/dist/executors/workspace.d.ts +10 -0
- package/dist/executors/workspace.js +47 -0
- package/dist/executors/workspace.js.map +1 -0
- package/dist/filters/evaluate.d.ts +77 -0
- package/dist/filters/evaluate.js +187 -0
- package/dist/filters/evaluate.js.map +1 -0
- package/dist/filters/fields.d.ts +35 -0
- package/dist/filters/fields.js +75 -0
- package/dist/filters/fields.js.map +1 -0
- package/dist/filters/index.d.ts +11 -0
- package/dist/filters/index.js +12 -0
- package/dist/filters/index.js.map +1 -0
- package/dist/filters/iso-date.d.ts +10 -0
- package/dist/filters/iso-date.js +42 -0
- package/dist/filters/iso-date.js.map +1 -0
- package/dist/filters/predicate.d.ts +24 -0
- package/dist/filters/predicate.js +178 -0
- package/dist/filters/predicate.js.map +1 -0
- package/dist/filters/priority.d.ts +51 -0
- package/dist/filters/priority.js +91 -0
- package/dist/filters/priority.js.map +1 -0
- package/dist/filters/pushdown.d.ts +12 -0
- package/dist/filters/pushdown.js +52 -0
- package/dist/filters/pushdown.js.map +1 -0
- package/dist/filters/shell-check.d.ts +110 -0
- package/dist/filters/shell-check.js +304 -0
- package/dist/filters/shell-check.js.map +1 -0
- package/dist/identities/github-app.d.ts +55 -0
- package/dist/identities/github-app.js +160 -0
- package/dist/identities/github-app.js.map +1 -0
- package/dist/identities/index.d.ts +6 -0
- package/dist/identities/index.js +7 -0
- package/dist/identities/index.js.map +1 -0
- package/dist/identities/jwt.d.ts +24 -0
- package/dist/identities/jwt.js +56 -0
- package/dist/identities/jwt.js.map +1 -0
- package/dist/lifecycle/context.d.ts +106 -0
- package/dist/lifecycle/context.js +170 -0
- package/dist/lifecycle/context.js.map +1 -0
- package/dist/lifecycle/engine.d.ts +185 -0
- package/dist/lifecycle/engine.js +551 -0
- package/dist/lifecycle/engine.js.map +1 -0
- package/dist/lifecycle/errors.d.ts +48 -0
- package/dist/lifecycle/errors.js +71 -0
- package/dist/lifecycle/errors.js.map +1 -0
- package/dist/lifecycle/index.d.ts +9 -0
- package/dist/lifecycle/index.js +9 -0
- package/dist/lifecycle/index.js.map +1 -0
- package/dist/lifecycle/performers.d.ts +66 -0
- package/dist/lifecycle/performers.js +179 -0
- package/dist/lifecycle/performers.js.map +1 -0
- package/dist/notifications/index.d.ts +6 -0
- package/dist/notifications/index.js +7 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/notifications/service.d.ts +115 -0
- package/dist/notifications/service.js +364 -0
- package/dist/notifications/service.js.map +1 -0
- package/dist/persistence/actions.d.ts +101 -0
- package/dist/persistence/actions.js +196 -0
- package/dist/persistence/actions.js.map +1 -0
- package/dist/persistence/blocks.d.ts +85 -0
- package/dist/persistence/blocks.js +140 -0
- package/dist/persistence/blocks.js.map +1 -0
- package/dist/persistence/cron-firings.d.ts +55 -0
- package/dist/persistence/cron-firings.js +70 -0
- package/dist/persistence/cron-firings.js.map +1 -0
- package/dist/persistence/database.d.ts +60 -0
- package/dist/persistence/database.js +124 -0
- package/dist/persistence/database.js.map +1 -0
- package/dist/persistence/errors.d.ts +39 -0
- package/dist/persistence/errors.js +67 -0
- package/dist/persistence/errors.js.map +1 -0
- package/dist/persistence/events.d.ts +72 -0
- package/dist/persistence/events.js +83 -0
- package/dist/persistence/events.js.map +1 -0
- package/dist/persistence/index.d.ts +18 -0
- package/dist/persistence/index.js +19 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/persistence/instance-lock.d.ts +26 -0
- package/dist/persistence/instance-lock.js +117 -0
- package/dist/persistence/instance-lock.js.map +1 -0
- package/dist/persistence/lock-keys.d.ts +16 -0
- package/dist/persistence/lock-keys.js +41 -0
- package/dist/persistence/lock-keys.js.map +1 -0
- package/dist/persistence/notifications.d.ts +113 -0
- package/dist/persistence/notifications.js +213 -0
- package/dist/persistence/notifications.js.map +1 -0
- package/dist/persistence/persistence.d.ts +46 -0
- package/dist/persistence/persistence.js +42 -0
- package/dist/persistence/persistence.js.map +1 -0
- package/dist/persistence/retention.d.ts +46 -0
- package/dist/persistence/retention.js +68 -0
- package/dist/persistence/retention.js.map +1 -0
- package/dist/persistence/runs.d.ts +215 -0
- package/dist/persistence/runs.js +417 -0
- package/dist/persistence/runs.js.map +1 -0
- package/dist/persistence/schema.d.ts +16 -0
- package/dist/persistence/schema.js +183 -0
- package/dist/persistence/schema.js.map +1 -0
- package/dist/persistence/sqlite.d.ts +49 -0
- package/dist/persistence/sqlite.js +131 -0
- package/dist/persistence/sqlite.js.map +1 -0
- package/dist/runs/controller.d.ts +307 -0
- package/dist/runs/controller.js +1078 -0
- package/dist/runs/controller.js.map +1 -0
- package/dist/runs/errors.d.ts +20 -0
- package/dist/runs/errors.js +26 -0
- package/dist/runs/errors.js.map +1 -0
- package/dist/runs/event-bus.d.ts +106 -0
- package/dist/runs/event-bus.js +105 -0
- package/dist/runs/event-bus.js.map +1 -0
- package/dist/runs/execution.d.ts +39 -0
- package/dist/runs/execution.js +146 -0
- package/dist/runs/execution.js.map +1 -0
- package/dist/runs/index.d.ts +12 -0
- package/dist/runs/index.js +13 -0
- package/dist/runs/index.js.map +1 -0
- package/dist/runs/retention.d.ts +64 -0
- package/dist/runs/retention.js +232 -0
- package/dist/runs/retention.js.map +1 -0
- package/dist/runs/workspace.d.ts +20 -0
- package/dist/runs/workspace.js +51 -0
- package/dist/runs/workspace.js.map +1 -0
- package/dist/scheduler/checks.d.ts +41 -0
- package/dist/scheduler/checks.js +111 -0
- package/dist/scheduler/checks.js.map +1 -0
- package/dist/scheduler/cron.d.ts +32 -0
- package/dist/scheduler/cron.js +83 -0
- package/dist/scheduler/cron.js.map +1 -0
- package/dist/scheduler/dry-run.d.ts +42 -0
- package/dist/scheduler/dry-run.js +167 -0
- package/dist/scheduler/dry-run.js.map +1 -0
- package/dist/scheduler/errors.d.ts +22 -0
- package/dist/scheduler/errors.js +22 -0
- package/dist/scheduler/errors.js.map +1 -0
- package/dist/scheduler/format.d.ts +3 -0
- package/dist/scheduler/format.js +73 -0
- package/dist/scheduler/format.js.map +1 -0
- package/dist/scheduler/index.d.ts +13 -0
- package/dist/scheduler/index.js +14 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/scheduler/planner.d.ts +88 -0
- package/dist/scheduler/planner.js +255 -0
- package/dist/scheduler/planner.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +160 -0
- package/dist/scheduler/scheduler.js +680 -0
- package/dist/scheduler/scheduler.js.map +1 -0
- package/dist/scheduler/state.d.ts +26 -0
- package/dist/scheduler/state.js +25 -0
- package/dist/scheduler/state.js.map +1 -0
- package/dist/scheduler/types.d.ts +197 -0
- package/dist/scheduler/types.js +3 -0
- package/dist/scheduler/types.js.map +1 -0
- package/dist/service/index.d.ts +6 -0
- package/dist/service/index.js +7 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/install.d.ts +93 -0
- package/dist/service/install.js +250 -0
- package/dist/service/install.js.map +1 -0
- package/dist/service/unit.d.ts +50 -0
- package/dist/service/unit.js +171 -0
- package/dist/service/unit.js.map +1 -0
- package/dist/sources/github/adapter.d.ts +99 -0
- package/dist/sources/github/adapter.js +336 -0
- package/dist/sources/github/adapter.js.map +1 -0
- package/dist/sources/github/fields.d.ts +8 -0
- package/dist/sources/github/fields.js +72 -0
- package/dist/sources/github/fields.js.map +1 -0
- package/dist/sources/github/http.d.ts +100 -0
- package/dist/sources/github/http.js +288 -0
- package/dist/sources/github/http.js.map +1 -0
- package/dist/sources/github/index.d.ts +6 -0
- package/dist/sources/github/index.js +7 -0
- package/dist/sources/github/index.js.map +1 -0
- package/dist/sources/github/pushdown.d.ts +14 -0
- package/dist/sources/github/pushdown.js +47 -0
- package/dist/sources/github/pushdown.js.map +1 -0
- package/dist/sources/github/refs.d.ts +17 -0
- package/dist/sources/github/refs.js +61 -0
- package/dist/sources/github/refs.js.map +1 -0
- package/dist/sources/index.d.ts +6 -0
- package/dist/sources/index.js +7 -0
- package/dist/sources/index.js.map +1 -0
- package/dist/ui/index.d.ts +12 -0
- package/dist/ui/index.js +28 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/public/app.css +239 -0
- package/dist/ui/public/favicon.svg +1 -0
- package/dist/ui/public/index.html +27 -0
- package/dist/ui/public/js/client/api.js +68 -0
- package/dist/ui/public/js/client/app.js +146 -0
- package/dist/ui/public/js/client/dom.js +34 -0
- package/dist/ui/public/js/client/page.js +9 -0
- package/dist/ui/public/js/client/pages/actions.js +35 -0
- package/dist/ui/public/js/client/pages/blocked.js +58 -0
- package/dist/ui/public/js/client/pages/config.js +126 -0
- package/dist/ui/public/js/client/pages/dashboard.js +175 -0
- package/dist/ui/public/js/client/pages/run.js +367 -0
- package/dist/ui/public/js/client/pages/runs.js +72 -0
- package/dist/ui/public/js/client/pages/views.js +80 -0
- package/dist/ui/public/js/client/pages/workflows.js +291 -0
- package/dist/ui/public/js/client/types.js +1 -0
- package/dist/ui/public/js/client/ui.js +152 -0
- package/dist/ui/public/js/shared/dom.js +77 -0
- package/dist/ui/public/js/shared/events.js +88 -0
- package/dist/ui/public/js/shared/format.js +213 -0
- package/dist/ui/public/js/shared/logs.js +136 -0
- package/dist/ui/public/js/shared/params.js +90 -0
- package/dist/ui/public/js/shared/route.js +36 -0
- package/dist/ui/public/js/shared/sort.js +70 -0
- package/dist/ui/public/js/shared/sse.js +193 -0
- package/dist/ui/public/js/shared/throttle.js +65 -0
- package/dist/views/index.d.ts +6 -0
- package/dist/views/index.js +7 -0
- package/dist/views/index.js.map +1 -0
- package/dist/views/service.d.ts +131 -0
- package/dist/views/service.js +264 -0
- package/dist/views/service.js.map +1 -0
- package/docs/api.md +239 -0
- package/docs/configuration-reference.md +1785 -0
- package/docs/cron-semantics.md +96 -0
- package/docs/manual-tests/github-fixture/config.yaml +30 -0
- package/docs/manual-tests/github-fixture/helpers.sh +93 -0
- package/docs/manual-tests/github-fixture/identities.yaml +18 -0
- package/docs/manual-tests/github-fixture/scripts/test-worker.sh +100 -0
- package/docs/manual-tests/github-fixture/sources.yaml +13 -0
- package/docs/manual-tests/github-fixture/views/dependencies.yaml +17 -0
- package/docs/manual-tests/github-fixture/views/needs-maintainer.yaml +17 -0
- package/docs/manual-tests/github-fixture/workflows/coder-test.yaml +76 -0
- package/docs/manual-tests/github-fixture/workflows/commenter-test.yaml +63 -0
- package/docs/manual-tests/github-fixture/workflows/reviewer-test.yaml +60 -0
- package/docs/manual-tests/github.md +1308 -0
- package/docs/manual-tests/process-supervision.md +64 -0
- package/docs/manual-tests/systemd.md +68 -0
- package/docs/operations.md +271 -0
- package/docs/worker-protocol.md +145 -0
- package/examples/config/config.yaml +35 -0
- package/examples/config/identities.yaml +18 -0
- package/examples/config/sources.yaml +13 -0
- package/examples/config/views/needs-maintainer.yaml +15 -0
- package/examples/config/workflows/coder-project-a.yaml +86 -0
- package/examples/config/workflows/deploy.yaml +15 -0
- package/examples/config/workflows/nightly-maintenance.yaml +13 -0
- package/package.json +75 -4
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cron slot computation on top of croner (Spec §5.5, §7, §24.7). Pure
|
|
3
|
+
* functions; the DST semantics are pinned by tests and documented in
|
|
4
|
+
* `docs/cron-semantics.md`.
|
|
5
|
+
*/
|
|
6
|
+
import { Cron } from 'croner';
|
|
7
|
+
/**
|
|
8
|
+
* Parse a cron expression for a time zone (croner syntax, 5 or 6 fields).
|
|
9
|
+
* @throws Error for invalid expressions/time zones (config validation rejects them earlier).
|
|
10
|
+
*/
|
|
11
|
+
export function parseCron(expression, timezone) {
|
|
12
|
+
const job = new Cron(expression, { paused: true, timezone });
|
|
13
|
+
return {
|
|
14
|
+
expression,
|
|
15
|
+
timezone,
|
|
16
|
+
next(after) {
|
|
17
|
+
// croner works with second precision: a reference inside a second is
|
|
18
|
+
// treated as that second, so `next` is strictly after `after`.
|
|
19
|
+
const next = job.nextRun(after);
|
|
20
|
+
return next && next.getTime() > after.getTime() ? next : null;
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** The next `count` slots strictly after `after`. */
|
|
25
|
+
export function nextSlots(schedule, after, count) {
|
|
26
|
+
const out = [];
|
|
27
|
+
let cursor = after;
|
|
28
|
+
while (out.length < count) {
|
|
29
|
+
const next = schedule.next(cursor);
|
|
30
|
+
if (!next)
|
|
31
|
+
break;
|
|
32
|
+
out.push(next);
|
|
33
|
+
cursor = next;
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* All slots in `(after, now]`, keeping only the most recent `keep` of them.
|
|
39
|
+
* Scanning is bounded by `maxScan`; if hit, scanning restarts closer to
|
|
40
|
+
* `now` so that the most recent slots are still found.
|
|
41
|
+
*/
|
|
42
|
+
export function dueSlots(schedule, after, now, options) {
|
|
43
|
+
const keep = Math.max(1, options.keep);
|
|
44
|
+
let slots = [];
|
|
45
|
+
let total = 0;
|
|
46
|
+
let scanned = 0;
|
|
47
|
+
let cursor = after;
|
|
48
|
+
let scanLimited = false;
|
|
49
|
+
for (;;) {
|
|
50
|
+
const next = schedule.next(cursor);
|
|
51
|
+
if (!next || next.getTime() > now.getTime())
|
|
52
|
+
break;
|
|
53
|
+
slots.push(next);
|
|
54
|
+
if (slots.length > keep)
|
|
55
|
+
slots = slots.slice(-keep);
|
|
56
|
+
total++;
|
|
57
|
+
cursor = next;
|
|
58
|
+
if (++scanned >= options.maxScan) {
|
|
59
|
+
// Too many slots (e.g. a per-second schedule after a long downtime):
|
|
60
|
+
// jump to a window right before `now` and only collect the latest ones.
|
|
61
|
+
scanLimited = true;
|
|
62
|
+
const windowStart = new Date(now.getTime() - estimateWindowMs(schedule, now, keep));
|
|
63
|
+
if (windowStart.getTime() <= cursor.getTime())
|
|
64
|
+
continue;
|
|
65
|
+
cursor = windowStart;
|
|
66
|
+
slots = [];
|
|
67
|
+
scanned = 0;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return { slots, total: Math.max(total, slots.length), scanLimited };
|
|
71
|
+
}
|
|
72
|
+
/** Rough time span that contains about `keep` slots before `now` (doubling search, bounded). */
|
|
73
|
+
function estimateWindowMs(schedule, now, keep) {
|
|
74
|
+
let span = 60_000;
|
|
75
|
+
for (let i = 0; i < 40; i++) {
|
|
76
|
+
const found = nextSlots(schedule, new Date(now.getTime() - span), keep + 1).filter((d) => d.getTime() <= now.getTime());
|
|
77
|
+
if (found.length >= keep)
|
|
78
|
+
return span;
|
|
79
|
+
span *= 2;
|
|
80
|
+
}
|
|
81
|
+
return span;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=cron.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron.js","sourceRoot":"","sources":["../../src/scheduler/cron.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow dry-run (Spec §19): source query, declarative filter analysis
|
|
3
|
+
* (incl. dependencies), priorities, locks/blocks and capacity – without
|
|
4
|
+
* workers, lifecycle actions, reservations or shell filters/conditions
|
|
5
|
+
* (reported as `not_evaluated`). Read-only.
|
|
6
|
+
*
|
|
7
|
+
* Differences to a real planning step (documented in the handoff):
|
|
8
|
+
* - Eligibility is evaluated before capacity, so every candidate shows its
|
|
9
|
+
* filter/lock/block status even when the limits are exhausted; capacity is
|
|
10
|
+
* then simulated in priority order (`pending_checks` candidates consume a
|
|
11
|
+
* slot, assuming their checks pass).
|
|
12
|
+
* - Eligible candidates of a disabled workflow / with closed controller gate
|
|
13
|
+
* are reported as `workflow_unavailable` / `gate_closed`, never `would_start`.
|
|
14
|
+
* - Only the given workflow is considered; higher-priority workflows that
|
|
15
|
+
* would take global slots first are not simulated.
|
|
16
|
+
*/
|
|
17
|
+
import { type Clock } from '../core/index.js';
|
|
18
|
+
import { type ConfigManager } from '../config/index.js';
|
|
19
|
+
import { type SourceLookup } from './planner.js';
|
|
20
|
+
import type { SchedulingState } from './state.js';
|
|
21
|
+
import type { DryRunResult, GateInfo } from './types.js';
|
|
22
|
+
/** Dependencies of {@link dryRunWorkflow}. */
|
|
23
|
+
export interface DryRunDeps {
|
|
24
|
+
config: ConfigManager;
|
|
25
|
+
sources: SourceLookup;
|
|
26
|
+
state: SchedulingState;
|
|
27
|
+
clock?: Clock;
|
|
28
|
+
/** Controller gate; omit when no controller runs (local CLI dry-run). */
|
|
29
|
+
gate?: () => GateInfo;
|
|
30
|
+
/** Additional notes (e.g. "no database"). */
|
|
31
|
+
notes?: readonly string[];
|
|
32
|
+
signal?: AbortSignal;
|
|
33
|
+
}
|
|
34
|
+
/** Number of upcoming cron slots shown. */
|
|
35
|
+
export declare const DRY_RUN_CRON_SLOTS = 5;
|
|
36
|
+
/** Number of recent cron firings shown. */
|
|
37
|
+
export declare const DRY_RUN_RECENT_FIRINGS = 10;
|
|
38
|
+
/**
|
|
39
|
+
* Dry-run one workflow.
|
|
40
|
+
* @throws UnknownWorkflowError
|
|
41
|
+
*/
|
|
42
|
+
export declare function dryRunWorkflow(deps: DryRunDeps, workflowId: string): Promise<DryRunResult>;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow dry-run (Spec §19): source query, declarative filter analysis
|
|
3
|
+
* (incl. dependencies), priorities, locks/blocks and capacity – without
|
|
4
|
+
* workers, lifecycle actions, reservations or shell filters/conditions
|
|
5
|
+
* (reported as `not_evaluated`). Read-only.
|
|
6
|
+
*
|
|
7
|
+
* Differences to a real planning step (documented in the handoff):
|
|
8
|
+
* - Eligibility is evaluated before capacity, so every candidate shows its
|
|
9
|
+
* filter/lock/block status even when the limits are exhausted; capacity is
|
|
10
|
+
* then simulated in priority order (`pending_checks` candidates consume a
|
|
11
|
+
* slot, assuming their checks pass).
|
|
12
|
+
* - Eligible candidates of a disabled workflow / with closed controller gate
|
|
13
|
+
* are reported as `workflow_unavailable` / `gate_closed`, never `would_start`.
|
|
14
|
+
* - Only the given workflow is considered; higher-priority workflows that
|
|
15
|
+
* would take global slots first are not simulated.
|
|
16
|
+
*/
|
|
17
|
+
import { systemClock } from '../core/index.js';
|
|
18
|
+
import { UnknownWorkflowError } from '../config/index.js';
|
|
19
|
+
import { sortCandidates } from '../filters/index.js';
|
|
20
|
+
import { notEvaluatedConditions } from './checks.js';
|
|
21
|
+
import { nextSlots, parseCron } from './cron.js';
|
|
22
|
+
import { checkEligibility, prepareSourceWorkflow } from './planner.js';
|
|
23
|
+
/** Number of upcoming cron slots shown. */
|
|
24
|
+
export const DRY_RUN_CRON_SLOTS = 5;
|
|
25
|
+
/** Number of recent cron firings shown. */
|
|
26
|
+
export const DRY_RUN_RECENT_FIRINGS = 10;
|
|
27
|
+
/**
|
|
28
|
+
* Dry-run one workflow.
|
|
29
|
+
* @throws UnknownWorkflowError
|
|
30
|
+
*/
|
|
31
|
+
export async function dryRunWorkflow(deps, workflowId) {
|
|
32
|
+
const eff = deps.config.getWorkflow(workflowId);
|
|
33
|
+
if (!eff)
|
|
34
|
+
throw new UnknownWorkflowError(workflowId);
|
|
35
|
+
const workflow = eff.config;
|
|
36
|
+
const now = (deps.clock ?? systemClock).now();
|
|
37
|
+
const gate = deps.gate ? deps.gate() : null;
|
|
38
|
+
const notes = [...(deps.notes ?? [])];
|
|
39
|
+
if (!eff.enabled)
|
|
40
|
+
notes.push('workflow is disabled: no automatic starts (manual starts remain possible)');
|
|
41
|
+
if (gate === null)
|
|
42
|
+
notes.push('controller state unknown (no running instance): pause/drain/readiness not considered');
|
|
43
|
+
else if (!gate.canStartAutomatically)
|
|
44
|
+
notes.push(`automatic starts are currently not possible: ${gate.reason ?? 'unknown'}`);
|
|
45
|
+
notes.push('shell filters and conditions are never executed in a dry-run (not_evaluated)');
|
|
46
|
+
const globalActive = deps.state.countActive();
|
|
47
|
+
const workflowActive = deps.state.countActive(workflowId);
|
|
48
|
+
const capacity = {
|
|
49
|
+
global: { active: globalActive, max: deps.config.maxConcurrent },
|
|
50
|
+
workflow: { active: workflowActive, max: eff.maxConcurrent },
|
|
51
|
+
};
|
|
52
|
+
const result = {
|
|
53
|
+
workflowId,
|
|
54
|
+
name: workflow.name,
|
|
55
|
+
trigger: workflow.trigger,
|
|
56
|
+
generatedAt: now.toISOString(),
|
|
57
|
+
enabled: eff.enabled,
|
|
58
|
+
workflowPriority: eff.priority,
|
|
59
|
+
capacity,
|
|
60
|
+
gate,
|
|
61
|
+
conditions: notEvaluatedConditions(workflow, 'workflow_condition'),
|
|
62
|
+
source: null,
|
|
63
|
+
candidates: [],
|
|
64
|
+
cron: null,
|
|
65
|
+
notes,
|
|
66
|
+
summary: { candidates: 0, wouldStart: 0, pendingChecks: 0, notStartable: 0 },
|
|
67
|
+
};
|
|
68
|
+
const trigger = workflow.trigger;
|
|
69
|
+
if (trigger.type === 'source') {
|
|
70
|
+
const prepared = await prepareSourceWorkflow(workflow, eff.priority, {
|
|
71
|
+
sources: deps.sources,
|
|
72
|
+
at: result.generatedAt,
|
|
73
|
+
...(deps.signal ? { signal: deps.signal } : {}),
|
|
74
|
+
});
|
|
75
|
+
result.source = {
|
|
76
|
+
sourceId: trigger.source,
|
|
77
|
+
polled: prepared.diagnosis.polled,
|
|
78
|
+
pushdown: prepared.diagnosis.pushdown,
|
|
79
|
+
error: prepared.diagnosis.error,
|
|
80
|
+
};
|
|
81
|
+
let simGlobal = globalActive;
|
|
82
|
+
let simWorkflow = workflowActive;
|
|
83
|
+
const ordered = [];
|
|
84
|
+
for (const candidate of sortCandidates(prepared.candidates)) {
|
|
85
|
+
const eligibility = await checkEligibility(candidate, {
|
|
86
|
+
state: deps.state,
|
|
87
|
+
checks: null,
|
|
88
|
+
workflowConditions: () => Promise.reject(new Error('shell checks are not executed in a dry-run')),
|
|
89
|
+
...(deps.signal ? { signal: deps.signal } : {}),
|
|
90
|
+
});
|
|
91
|
+
const diag = candidate.diagnosis;
|
|
92
|
+
ordered.push(diag);
|
|
93
|
+
if (!eligibility.eligible)
|
|
94
|
+
continue;
|
|
95
|
+
if (!eff.enabled) {
|
|
96
|
+
diag.decision = 'workflow_unavailable';
|
|
97
|
+
diag.reason = 'eligible, but the workflow is disabled (no automatic starts)';
|
|
98
|
+
}
|
|
99
|
+
else if (gate && !gate.canStartAutomatically) {
|
|
100
|
+
diag.decision = 'gate_closed';
|
|
101
|
+
diag.reason = `eligible, but automatic starts are currently not possible (${gate.reason ?? 'unknown'})`;
|
|
102
|
+
}
|
|
103
|
+
else if (simGlobal >= capacity.global.max) {
|
|
104
|
+
diag.decision = 'global_limit';
|
|
105
|
+
diag.reason = `global limit reached (${simGlobal}/${capacity.global.max}, incl. candidates above)`;
|
|
106
|
+
}
|
|
107
|
+
else if (simWorkflow >= capacity.workflow.max) {
|
|
108
|
+
diag.decision = 'workflow_limit';
|
|
109
|
+
diag.reason = `workflow limit reached (${simWorkflow}/${capacity.workflow.max}, incl. candidates above)`;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
simGlobal++;
|
|
113
|
+
simWorkflow++;
|
|
114
|
+
diag.decision = eligibility.pendingChecks ? 'pending_checks' : 'would_start';
|
|
115
|
+
diag.reason = eligibility.pendingChecks
|
|
116
|
+
? 'declaratively eligible; would start if the shell filter/conditions pass'
|
|
117
|
+
: 'eligible; would start';
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
result.candidates = [...ordered, ...prepared.rejected];
|
|
121
|
+
}
|
|
122
|
+
else if (trigger.type === 'schedule') {
|
|
123
|
+
const schedule = parseCron(trigger.cron, trigger.timezone);
|
|
124
|
+
const block = deps.state.activeBlock(workflowId, null);
|
|
125
|
+
let forecast;
|
|
126
|
+
let reason = null;
|
|
127
|
+
if (!eff.enabled)
|
|
128
|
+
forecast = 'skipped_disabled';
|
|
129
|
+
else if (gate && !gate.canStartAutomatically && gate.reason)
|
|
130
|
+
forecast = `skipped_${gate.reason}`;
|
|
131
|
+
else if (globalActive >= capacity.global.max || workflowActive >= capacity.workflow.max) {
|
|
132
|
+
forecast = 'skipped_limit';
|
|
133
|
+
reason = `active runs: global ${globalActive}/${capacity.global.max}, workflow ${workflowActive}/${capacity.workflow.max}`;
|
|
134
|
+
}
|
|
135
|
+
else if (block) {
|
|
136
|
+
forecast = 'skipped_blocked';
|
|
137
|
+
reason = `retry block ${block.id}: ${block.reason}`;
|
|
138
|
+
}
|
|
139
|
+
else if (workflow.conditions.workflow.length > 0) {
|
|
140
|
+
forecast = 'pending_checks';
|
|
141
|
+
reason = 'would start if the workflow conditions pass';
|
|
142
|
+
}
|
|
143
|
+
else
|
|
144
|
+
forecast = 'would_start';
|
|
145
|
+
result.cron = {
|
|
146
|
+
cron: trigger.cron,
|
|
147
|
+
timezone: trigger.timezone,
|
|
148
|
+
nextSlots: nextSlots(schedule, now, DRY_RUN_CRON_SLOTS).map((d) => d.toISOString()),
|
|
149
|
+
nextSlotForecast: forecast,
|
|
150
|
+
forecastReason: reason,
|
|
151
|
+
recentFirings: deps.state.recentCronFirings(workflowId, DRY_RUN_RECENT_FIRINGS),
|
|
152
|
+
blockId: block?.id ?? null,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
notes.push('manual workflow: runs only start manually (filters, conditions, blocks and limits do not apply)');
|
|
157
|
+
}
|
|
158
|
+
const counted = result.candidates;
|
|
159
|
+
result.summary = {
|
|
160
|
+
candidates: counted.length,
|
|
161
|
+
wouldStart: counted.filter((c) => c.decision === 'would_start').length,
|
|
162
|
+
pendingChecks: counted.filter((c) => c.decision === 'pending_checks').length,
|
|
163
|
+
notStartable: counted.filter((c) => c.decision !== 'would_start' && c.decision !== 'pending_checks').length,
|
|
164
|
+
};
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=dry-run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dry-run.js","sourceRoot":"","sources":["../../src/scheduler/dry-run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Errors of the scheduler's manual start / dry-run API. All extend
|
|
3
|
+
* {@link OrchestratorError}; WI-10 maps the stable `code` to HTTP:
|
|
4
|
+
*
|
|
5
|
+
* | code | HTTP |
|
|
6
|
+
* |---|---|
|
|
7
|
+
* | `manual_item_required`, `manual_item_not_supported`, `manual_item_invalid_ref`, `invalid_parameters` | 400 |
|
|
8
|
+
* | `manual_item_not_found` | 404 |
|
|
9
|
+
* | `source_unavailable` | 502 |
|
|
10
|
+
* | `scheduler_not_accepting` | 503 |
|
|
11
|
+
*
|
|
12
|
+
* Unknown workflows throw `UnknownWorkflowError` (config, `config_unknown_workflow` → 404);
|
|
13
|
+
* an active lock throws `LockConflictError` (persistence, `lock_conflict` → 409).
|
|
14
|
+
*/
|
|
15
|
+
import { OrchestratorError } from '../core/index.js';
|
|
16
|
+
/** Codes of {@link SchedulerError}. */
|
|
17
|
+
export type SchedulerErrorCode = 'manual_item_required' | 'manual_item_not_supported' | 'manual_item_invalid_ref' | 'manual_item_not_found' | 'invalid_parameters' | 'source_unavailable' | 'scheduler_not_accepting';
|
|
18
|
+
/** Error of the scheduler API (see module docs for the HTTP mapping). */
|
|
19
|
+
export declare class SchedulerError extends OrchestratorError {
|
|
20
|
+
readonly code: SchedulerErrorCode;
|
|
21
|
+
constructor(code: SchedulerErrorCode, message: string, details?: Record<string, unknown>, cause?: unknown);
|
|
22
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Errors of the scheduler's manual start / dry-run API. All extend
|
|
3
|
+
* {@link OrchestratorError}; WI-10 maps the stable `code` to HTTP:
|
|
4
|
+
*
|
|
5
|
+
* | code | HTTP |
|
|
6
|
+
* |---|---|
|
|
7
|
+
* | `manual_item_required`, `manual_item_not_supported`, `manual_item_invalid_ref`, `invalid_parameters` | 400 |
|
|
8
|
+
* | `manual_item_not_found` | 404 |
|
|
9
|
+
* | `source_unavailable` | 502 |
|
|
10
|
+
* | `scheduler_not_accepting` | 503 |
|
|
11
|
+
*
|
|
12
|
+
* Unknown workflows throw `UnknownWorkflowError` (config, `config_unknown_workflow` → 404);
|
|
13
|
+
* an active lock throws `LockConflictError` (persistence, `lock_conflict` → 409).
|
|
14
|
+
*/
|
|
15
|
+
import { OrchestratorError } from '../core/index.js';
|
|
16
|
+
/** Error of the scheduler API (see module docs for the HTTP mapping). */
|
|
17
|
+
export class SchedulerError extends OrchestratorError {
|
|
18
|
+
constructor(code, message, details, cause) {
|
|
19
|
+
super(code, message, { ...(details ? { details } : {}), ...(cause !== undefined ? { cause } : {}) });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/scheduler/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAYrD,yEAAyE;AACzE,MAAM,OAAO,cAAe,SAAQ,iBAAiB;IAGnD,YAAY,IAAwB,EAAE,OAAe,EAAE,OAAiC,EAAE,KAAe;QACvG,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACvG,CAAC;CACF"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
function traceLines(trace, indent) {
|
|
2
|
+
const value = String(trace.value);
|
|
3
|
+
switch (trace.kind) {
|
|
4
|
+
case 'all':
|
|
5
|
+
case 'any':
|
|
6
|
+
return [`${indent}${trace.kind}: ${value}`, ...trace.children.flatMap((c) => traceLines(c, `${indent} `))];
|
|
7
|
+
case 'not':
|
|
8
|
+
return [`${indent}not: ${value}`, ...traceLines(trace.child, `${indent} `)];
|
|
9
|
+
case 'predicate': {
|
|
10
|
+
const actual = 'actual' in trace && trace.actual !== undefined ? ` (actual ${JSON.stringify(trace.actual)})` : '';
|
|
11
|
+
const why = trace.reason ? ` – ${trace.reason}` : '';
|
|
12
|
+
return [`${indent}${trace.field} ${trace.operator} ${JSON.stringify(trace.expected)}: ${value}${actual}${why}`];
|
|
13
|
+
}
|
|
14
|
+
case 'invalid':
|
|
15
|
+
return [`${indent}invalid rule: ${value} – ${trace.reason}`];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function checkLine(c) {
|
|
19
|
+
const what = c.kind === 'shell_filter' ? 'shell filter' : `${c.kind.replace('_', ' ')} ${c.index}`;
|
|
20
|
+
const value = c.value === 'not_evaluated' ? 'unknown / not evaluated' : String(c.value);
|
|
21
|
+
return `${what} ${c.command}: ${value}${c.error ? ` – ${c.error}` : ''}`;
|
|
22
|
+
}
|
|
23
|
+
function candidateLines(c, n) {
|
|
24
|
+
const title = c.title ? ` "${c.title}"` : '';
|
|
25
|
+
const lines = [
|
|
26
|
+
`${String(n).padStart(3)}. ${c.itemKey}${title}`,
|
|
27
|
+
` priority ${c.workflowPriority}/${c.itemPriority}${c.matchedPriorityRule !== null ? ` (rule ${c.matchedPriorityRule})` : ''} → ${c.decision}${c.reason ? `: ${c.reason}` : ''}`,
|
|
28
|
+
` ${c.url}`,
|
|
29
|
+
];
|
|
30
|
+
if (c.filter)
|
|
31
|
+
lines.push(' filter:', ...traceLines(c.filter, ' '));
|
|
32
|
+
if (c.shellFilter)
|
|
33
|
+
lines.push(` ${checkLine(c.shellFilter)}`);
|
|
34
|
+
for (const ic of c.itemConditions)
|
|
35
|
+
lines.push(` ${checkLine(ic)}`);
|
|
36
|
+
return lines;
|
|
37
|
+
}
|
|
38
|
+
/** Render a dry-run result as plain text. */
|
|
39
|
+
export function formatDryRun(r) {
|
|
40
|
+
const t = r.trigger;
|
|
41
|
+
const trigger = t.type === 'source' ? `source ${t.source}` : t.type === 'schedule' ? `schedule '${t.cron}' (${t.timezone})` : 'manual';
|
|
42
|
+
const lines = [
|
|
43
|
+
`Dry-run of workflow '${r.workflowId}' (${r.name}) at ${r.generatedAt}`,
|
|
44
|
+
` trigger: ${trigger}`,
|
|
45
|
+
` enabled: ${r.enabled ? 'yes' : 'no'}, workflow priority: ${r.workflowPriority}`,
|
|
46
|
+
` capacity: workflow ${r.capacity.workflow.active}/${r.capacity.workflow.max} active, global ${r.capacity.global.active}/${r.capacity.global.max} active`,
|
|
47
|
+
];
|
|
48
|
+
if (r.gate)
|
|
49
|
+
lines.push(` automatic starts: ${r.gate.canStartAutomatically ? 'possible' : `not possible (${r.gate.reason ?? 'unknown'})`}`);
|
|
50
|
+
for (const c of r.conditions)
|
|
51
|
+
lines.push(` ${checkLine(c)}`);
|
|
52
|
+
if (r.source) {
|
|
53
|
+
lines.push(` source ${r.source.sourceId}: ${r.source.polled} item(s) polled${r.source.pushdown ? `, pushdown ${JSON.stringify(r.source.pushdown)}` : ''}`);
|
|
54
|
+
if (r.source.error)
|
|
55
|
+
lines.push(` SOURCE ERROR: ${r.source.error}`);
|
|
56
|
+
lines.push('', `Candidates (${r.summary.candidates}): ${r.summary.wouldStart} would start, ${r.summary.pendingChecks} pending checks, ${r.summary.notStartable} not startable`);
|
|
57
|
+
r.candidates.forEach((c, i) => lines.push(...candidateLines(c, i + 1)));
|
|
58
|
+
}
|
|
59
|
+
if (r.cron) {
|
|
60
|
+
lines.push(` next slots: ${r.cron.nextSlots.join(', ') || '(none)'}`);
|
|
61
|
+
lines.push(` next slot: ${r.cron.nextSlotForecast}${r.cron.forecastReason ? ` – ${r.cron.forecastReason}` : ''}`);
|
|
62
|
+
if (r.cron.recentFirings.length > 0) {
|
|
63
|
+
lines.push(' recent slots:');
|
|
64
|
+
for (const f of r.cron.recentFirings) {
|
|
65
|
+
lines.push(` ${f.scheduledFor} ${f.decision}${f.runId ? ` (${f.runId})` : ''}${f.reason ? ` – ${f.reason}` : ''}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (r.notes.length > 0)
|
|
70
|
+
lines.push('', 'Notes:', ...r.notes.map((n) => ` - ${n}`));
|
|
71
|
+
return `${lines.join('\n')}\n`;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/scheduler/format.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component `scheduler` – public API (WI-09): polling loop for source
|
|
3
|
+
* workflows, cron trigger, manual start, dry-run and planning diagnostics.
|
|
4
|
+
* Other components import from this module only.
|
|
5
|
+
*/
|
|
6
|
+
export { Scheduler, type ManualStartRequest, type ManualStartResult, type SchedulerOptions, type SchedulerRunController, } from './scheduler.js';
|
|
7
|
+
export { dryRunWorkflow, DRY_RUN_CRON_SLOTS, DRY_RUN_RECENT_FIRINGS, type DryRunDeps } from './dry-run.js';
|
|
8
|
+
export { formatDryRun } from './format.js';
|
|
9
|
+
export { SchedulerError, type SchedulerErrorCode } from './errors.js';
|
|
10
|
+
export { repositoryState, emptyState, type SchedulingState } from './state.js';
|
|
11
|
+
export { parseCron, nextSlots, dueSlots, type CronSchedule, type DueSlots } from './cron.js';
|
|
12
|
+
export { cheapOnly, verifyItemFor, type SourceLookup } from './planner.js';
|
|
13
|
+
export * from './types.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component `scheduler` – public API (WI-09): polling loop for source
|
|
3
|
+
* workflows, cron trigger, manual start, dry-run and planning diagnostics.
|
|
4
|
+
* Other components import from this module only.
|
|
5
|
+
*/
|
|
6
|
+
export { Scheduler, } from './scheduler.js';
|
|
7
|
+
export { dryRunWorkflow, DRY_RUN_CRON_SLOTS, DRY_RUN_RECENT_FIRINGS } from './dry-run.js';
|
|
8
|
+
export { formatDryRun } from './format.js';
|
|
9
|
+
export { SchedulerError } from './errors.js';
|
|
10
|
+
export { repositoryState, emptyState } from './state.js';
|
|
11
|
+
export { parseCron, nextSlots, dueSlots } from './cron.js';
|
|
12
|
+
export { cheapOnly, verifyItemFor } from './planner.js';
|
|
13
|
+
export * from './types.js';
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scheduler/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,SAAS,GAKV,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,sBAAsB,EAAmB,MAAM,cAAc,CAAC;AAC3G,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,cAAc,EAA2B,MAAM,aAAa,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAwB,MAAM,YAAY,CAAC;AAC/E,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAoC,MAAM,WAAW,CAAC;AAC7F,OAAO,EAAE,SAAS,EAAE,aAAa,EAAqB,MAAM,cAAc,CAAC;AAC3E,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Candidate discovery and eligibility for source workflows (Spec §7 steps
|
|
3
|
+
* 1–5), shared by the planning step and the dry-run.
|
|
4
|
+
*
|
|
5
|
+
* - Step 1: poll the source with the pushed-down part of the filter and
|
|
6
|
+
* evaluate the filter with CHEAP fields only. Strong Kleene logic is
|
|
7
|
+
* monotonic, so a cheap `false` is final (item dropped) and a cheap `true`
|
|
8
|
+
* is final; only a cheap `unknown` needs the expensive fields (step 5).
|
|
9
|
+
* - Step 2: de-duplicate by `(source, item, workflow)`.
|
|
10
|
+
* - Step 3: item priority (same field source → one batch of expensive fields).
|
|
11
|
+
* - Step 4: active lock / retry block of the workflow+item.
|
|
12
|
+
* - Step 5 (lazy): workflow conditions (once per step), expensive declarative
|
|
13
|
+
* filter, shell filter, item conditions. The dry-run never executes shell
|
|
14
|
+
* checks: they are reported as `not_evaluated`.
|
|
15
|
+
*/
|
|
16
|
+
import { type SourceAdapter, type SourceItem } from '../core/index.js';
|
|
17
|
+
import type { WorkflowConfig } from '../config/index.js';
|
|
18
|
+
import { type FieldSource, type FilterEvaluation, type PrioritizedCandidate } from '../filters/index.js';
|
|
19
|
+
import { type ChecksOutcome, type SchedulerChecks } from './checks.js';
|
|
20
|
+
import type { SchedulingState } from './state.js';
|
|
21
|
+
import type { CandidateDiagnosis, WorkflowPlanningDiagnosis } from './types.js';
|
|
22
|
+
/** Resolves a configured source ID to its adapter. */
|
|
23
|
+
export type SourceLookup = (sourceId: string) => SourceAdapter | undefined;
|
|
24
|
+
/** A candidate that passed the cheap filter (or whose filter needs expensive fields). */
|
|
25
|
+
export interface PreparedCandidate extends PrioritizedCandidate {
|
|
26
|
+
itemKey: string;
|
|
27
|
+
workflow: WorkflowConfig;
|
|
28
|
+
adapter: SourceAdapter;
|
|
29
|
+
item: SourceItem;
|
|
30
|
+
/** Memoizing field source of this planning step (expensive fields fetched at most once). */
|
|
31
|
+
fields: FieldSource;
|
|
32
|
+
/** Cheap-only filter evaluation; `null` if the workflow has no filter. */
|
|
33
|
+
cheap: FilterEvaluation | null;
|
|
34
|
+
diagnosis: CandidateDiagnosis;
|
|
35
|
+
}
|
|
36
|
+
/** Result of {@link prepareSourceWorkflow}. */
|
|
37
|
+
export interface PreparedWorkflow {
|
|
38
|
+
diagnosis: WorkflowPlanningDiagnosis;
|
|
39
|
+
/** Candidates to consider, unsorted. */
|
|
40
|
+
candidates: PreparedCandidate[];
|
|
41
|
+
/** Items rejected by the cheap filter (diagnosis only). */
|
|
42
|
+
rejected: CandidateDiagnosis[];
|
|
43
|
+
}
|
|
44
|
+
/** Field source that treats expensive fields as unknown without resolving them. */
|
|
45
|
+
export declare function cheapOnly(fields: FieldSource): FieldSource;
|
|
46
|
+
/** Cache of `listCandidates` calls within one planning step: `(source, pushdown) → items`. */
|
|
47
|
+
export type ListCache = Map<string, Promise<SourceItem[]>>;
|
|
48
|
+
/**
|
|
49
|
+
* Steps 1–3 for one source workflow: poll, de-duplicate, cheap filter, item
|
|
50
|
+
* priority. Never throws; source problems end up in the diagnosis
|
|
51
|
+
* (`status: 'source_error'`) without affecting other workflows.
|
|
52
|
+
*/
|
|
53
|
+
export declare function prepareSourceWorkflow(workflow: WorkflowConfig, workflowPriority: number, options: {
|
|
54
|
+
sources: SourceLookup;
|
|
55
|
+
at: string;
|
|
56
|
+
listCache?: ListCache;
|
|
57
|
+
signal?: AbortSignal;
|
|
58
|
+
}): Promise<PreparedWorkflow>;
|
|
59
|
+
/** Outcome of {@link checkEligibility}. */
|
|
60
|
+
export type Eligibility =
|
|
61
|
+
/** Startable now; `pendingChecks` = shell checks were skipped (dry-run). */
|
|
62
|
+
{
|
|
63
|
+
eligible: true;
|
|
64
|
+
pendingChecks: boolean;
|
|
65
|
+
} | {
|
|
66
|
+
eligible: false;
|
|
67
|
+
};
|
|
68
|
+
/** How {@link checkEligibility} treats shell checks. */
|
|
69
|
+
export interface EligibilityContext {
|
|
70
|
+
state: SchedulingState;
|
|
71
|
+
/** `null` = dry-run: shell filter and conditions are not executed. */
|
|
72
|
+
checks: SchedulerChecks | null;
|
|
73
|
+
/** Workflow conditions of the current step (memoized by the caller); only called in live mode. */
|
|
74
|
+
workflowConditions(workflow: WorkflowConfig): Promise<ChecksOutcome>;
|
|
75
|
+
signal?: AbortSignal;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Steps 4–5 for one candidate (lock, block, workflow conditions, expensive
|
|
79
|
+
* filter, shell filter, item conditions). Updates `candidate.diagnosis` with
|
|
80
|
+
* decision/reason for rejected candidates. Capacity is checked by the caller.
|
|
81
|
+
*/
|
|
82
|
+
export declare function checkEligibility(candidate: PreparedCandidate, ctx: EligibilityContext): Promise<Eligibility>;
|
|
83
|
+
/**
|
|
84
|
+
* Re-check for the item re-read by the run controller right before `on_start`
|
|
85
|
+
* (Spec §7 races): the cheap part of the filter on the fresh item. `false`
|
|
86
|
+
* cancels the run without hooks; `unknown` (expensive fields) does not.
|
|
87
|
+
*/
|
|
88
|
+
export declare function verifyItemFor(workflow: WorkflowConfig, adapter: SourceAdapter): ((item: SourceItem) => Promise<boolean>) | undefined;
|