@kici-dev/orchestrator 0.1.27 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__test-helpers__/mock-db.d.ts +2 -0
- package/dist/agent/dispatcher.d.ts +52 -2
- package/dist/agent/host-roster-reaper.d.ts +1 -2
- package/dist/agent/host-roster.d.ts +34 -0
- package/dist/agent/ownership-refusal.d.ts +12 -0
- package/dist/agent/ownership-tracker.d.ts +64 -16
- package/dist/agent/token-store.d.ts +13 -0
- package/dist/agent-packaging/availability.d.ts +27 -0
- package/dist/agent-packaging/build-package.d.ts +16 -0
- package/dist/agent-packaging/download.d.ts +30 -0
- package/dist/agent-packaging/index.d.ts +9 -0
- package/dist/agent-packaging/install-closure.d.ts +30 -0
- package/dist/agent-packaging/node-binary.d.ts +26 -0
- package/dist/agent-packaging/refresh.d.ts +50 -0
- package/dist/agent-packaging/store.d.ts +15 -0
- package/dist/agent-packaging/upload.d.ts +24 -0
- package/dist/app-on-error.d.ts +29 -0
- package/dist/app.d.ts +56 -4
- package/dist/artifacts/artifact-store.d.ts +233 -0
- package/dist/artifacts/failure-messages.d.ts +46 -0
- package/dist/audit/access-log.d.ts +18 -1
- package/dist/cache/dep-cache.d.ts +15 -0
- package/dist/cache/user-cache.d.ts +37 -0
- package/dist/cancel/cancel-run.d.ts +10 -3
- package/dist/cancel/dashboard-cancel-handler.d.ts +19 -0
- package/dist/cli/api-client.d.ts +44 -1
- package/dist/cli/commands/agent-package.d.ts +34 -0
- package/dist/cli/commands/check-run.d.ts +26 -0
- package/dist/cli/commands/cluster-settings.d.ts +55 -0
- package/dist/cli/commands/dashboard-encryption-key.d.ts +3 -0
- package/dist/cli/commands/db-backup.d.ts +71 -0
- package/dist/cli/commands/orchestrator-service/drain.d.ts +31 -0
- package/dist/cli/commands/orchestrator-service/index.d.ts +7 -4
- package/dist/cli/commands/orchestrator-service/install-env.d.ts +58 -0
- package/dist/cli/commands/secret.d.ts +45 -1
- package/dist/cli/commands/shared/admin-cli-access-log.d.ts +46 -0
- package/dist/cli/commands/shared/versioned-upgrade.d.ts +65 -2
- package/dist/cli/commands/signing-key.d.ts +3 -0
- package/dist/cli/commands/source.d.ts +12 -0
- package/dist/cli/commands/token.d.ts +9 -0
- package/dist/cli/commands/trust-policy.d.ts +48 -0
- package/dist/cli/join.d.ts +1 -1
- package/dist/cli/service/index.d.ts +2 -2
- package/dist/cli/service/instance/manifest.d.ts +17 -0
- package/dist/cli/service/instance/resolve.d.ts +11 -0
- package/dist/cli/wizard/orchestrator-wizard.d.ts +39 -11
- package/dist/cli.js +9921 -3409
- package/dist/cluster/cluster-settings-reader.d.ts +78 -0
- package/dist/cluster/coordinator.d.ts +81 -9
- package/dist/cluster/join-client.d.ts +1 -1
- package/dist/cluster/leader-gated-scheduler.d.ts +50 -0
- package/dist/cluster/orphan-recovery.d.ts +14 -0
- package/dist/cluster/peer-client.d.ts +12 -2
- package/dist/cluster/peer-handler.d.ts +15 -4
- package/dist/cluster/peer-registry.d.ts +12 -0
- package/dist/cluster/verified-issuer-poller.d.ts +11 -0
- package/dist/cluster/verified-issuer.d.ts +63 -0
- package/dist/cold-store/tables/access-log.d.ts +1 -1
- package/dist/cold-store/tables/event-log.d.ts +1 -1
- package/dist/cold-store/tables/execution-jobs.d.ts +1 -1
- package/dist/cold-store/tables/execution-runs.d.ts +1 -1
- package/dist/cold-store/tables/execution-steps.d.ts +1 -1
- package/dist/cold-store/tables/secret-audit-log.d.ts +1 -1
- package/dist/config/loader.d.ts +1 -1
- package/dist/config/resolver.d.ts +2 -1
- package/dist/config/schema.d.ts +9 -6
- package/dist/config/types.d.ts +5 -2
- package/dist/config.d.ts +366 -53
- package/dist/contexts/context-store.d.ts +21 -8
- package/dist/contexts/glob-specificity.d.ts +30 -0
- package/dist/contexts/held-runs.d.ts +51 -19
- package/dist/contexts/protection/aggregate.d.ts +2 -2
- package/dist/contexts/protection/concurrency-gate.d.ts +0 -3
- package/dist/contexts/protection/reviewer-gate.d.ts +0 -3
- package/dist/contexts/protection/satisfiability.d.ts +1 -1
- package/dist/contexts/protection/trust-gate.d.ts +0 -3
- package/dist/contexts/protection/wait-timer-gate.d.ts +0 -3
- package/dist/cron/cron-scheduler.d.ts +24 -4
- package/dist/cron/cron-store.d.ts +21 -7
- package/dist/dashboard/attestation-filters.d.ts +92 -74
- package/dist/dashboard/handler.d.ts +35 -1
- package/dist/db/migration-test-harness.d.ts +41 -0
- package/dist/db/migrations/069_reroute_tunables.d.ts +21 -0
- package/dist/db/migrations/070_execution_runs_failure_class.d.ts +4 -0
- package/dist/db/migrations/071_batch_accumulation.d.ts +26 -0
- package/dist/db/migrations/072_dispatch_queue_run_id_index.d.ts +15 -0
- package/dist/db/migrations/073_org_settings_ingest_concurrency.d.ts +13 -0
- package/dist/db/migrations/074_normalize_zero_concurrency_limit.d.ts +13 -0
- package/dist/db/migrations/075_ingest_overflow_buffer.d.ts +16 -0
- package/dist/db/migrations/076_artifacts.d.ts +19 -0
- package/dist/db/migrations/077_backup_runs.d.ts +13 -0
- package/dist/db/migrations/078_org_settings_backup_staleness.d.ts +12 -0
- package/dist/db/migrations/079_org_settings_scaler_spawn_timeout.d.ts +14 -0
- package/dist/db/migrations/080_cluster_settings.d.ts +17 -0
- package/dist/db/migrations/081_org_settings_queue_timeout.d.ts +19 -0
- package/dist/db/migrations/082_host_s3_reachable.d.ts +16 -0
- package/dist/db/migrations/083_org_settings_artifact_caps.d.ts +18 -0
- package/dist/db/migrations/084_orchestrator_signing_keys.d.ts +20 -0
- package/dist/db/migrations/085_cluster_settings_reroute_flap_grace_ms.d.ts +12 -0
- package/dist/db/migrations/086_cluster_settings_max_fanout_hosts.d.ts +12 -0
- package/dist/db/migrations/087_cluster_settings_event_router_rate_limit.d.ts +12 -0
- package/dist/db/migrations/088_cluster_settings_cache_max_tarball_bytes.d.ts +12 -0
- package/dist/db/migrations/089_cluster_settings_cache_ttl_days.d.ts +12 -0
- package/dist/db/migrations/090_cluster_settings_concurrency_wait_timeout_ms.d.ts +12 -0
- package/dist/db/migrations/091_cluster_settings_agent_token_ttl_ms.d.ts +12 -0
- package/dist/db/migrations/092_cluster_settings_version.d.ts +16 -0
- package/dist/db/migrations/093_org_settings_sandbox_allowlist.d.ts +4 -0
- package/dist/db/migrations/094_dashboard_encryption_keys.d.ts +21 -0
- package/dist/db/migrations/095_dashboard_write_policy_tristate.d.ts +20 -0
- package/dist/db/migrations/096_multi_schedule_cron_last_fired.d.ts +4 -0
- package/dist/db/migrations/097_execution_runs_pr_number.d.ts +4 -0
- package/dist/db/migrations/098_execution_runs_customer_id.d.ts +4 -0
- package/dist/db/migrations/099_cluster_settings_dashboard_verified_issuer.d.ts +21 -0
- package/dist/db/migrations/100_held_runs_hold_type_vocabulary.d.ts +31 -0
- package/dist/db/migrations/101_contexts_hold_expiry_drop_default.d.ts +31 -0
- package/dist/db/migrations/102_dispatch_queue_agent_id.d.ts +20 -0
- package/dist/db/migrations/103_cluster_settings_ownership_db_check_timeout_ms.d.ts +20 -0
- package/dist/db/migrations/104_check_run_terminal_sent.d.ts +22 -0
- package/dist/db/migrations/105_org_trust_policy.d.ts +19 -0
- package/dist/db/migrations/106_cluster_settings_check_run_tracking_ttl_days.d.ts +18 -0
- package/dist/db/migrations/107_check_run_tracking_updated_at_index.d.ts +23 -0
- package/dist/db/migrations/108_unroutable_fast_fail.d.ts +4 -0
- package/dist/db/repos/dashboard-encryption-keys-repo.d.ts +48 -0
- package/dist/db/repos/signing-keys-repo.d.ts +34 -0
- package/dist/db/types.d.ts +441 -7
- package/dist/deployment/deployment-identity.d.ts +87 -2
- package/dist/diagnostics/checks/backup.d.ts +18 -0
- package/dist/diagnostics/checks/index.d.ts +2 -1
- package/dist/diagnostics/fleet-collector.d.ts +1 -1
- package/dist/drain/drain-controller.d.ts +52 -0
- package/dist/events/batch-accumulator.d.ts +63 -0
- package/dist/events/circuit-breaker.d.ts +9 -3
- package/dist/events/event-emitter.d.ts +31 -0
- package/dist/events/event-retry-scanner.d.ts +12 -2
- package/dist/events/event-router.d.ts +29 -0
- package/dist/firecracker/host-network.d.ts +2 -0
- package/dist/firecracker/net-interfaces.d.ts +14 -0
- package/dist/github-app-name-refresher/github-app-name-refresher.d.ts +18 -8
- package/dist/index.d.ts +2 -0
- package/dist/index.js +654 -29
- package/dist/lockfile-cache.d.ts +4 -0
- package/dist/lockfile-validate.d.ts +16 -9
- package/dist/metrics/prometheus.d.ts +113 -15
- package/dist/oidc/aws-kms-signer.d.ts +37 -0
- package/dist/oidc/command-signer.d.ts +23 -0
- package/dist/oidc/db-signer.d.ts +48 -0
- package/dist/oidc/id-token-claims.d.ts +22 -9
- package/dist/oidc/jwt.d.ts +5 -2
- package/dist/oidc/local-dev-signer.d.ts +1 -1
- package/dist/oidc/oidc-mint-registration.d.ts +27 -11
- package/dist/oidc/orchestrator-mint.d.ts +97 -0
- package/dist/oidc/orchestrator-signer-factory.d.ts +33 -0
- package/dist/oidc/reconcile-signing-key.d.ts +21 -0
- package/dist/oidc/signer.d.ts +25 -0
- package/dist/oidc/signing-key-status.d.ts +23 -0
- package/dist/orchestrator-core.d.ts +42 -2
- package/dist/pipeline/decorating-secret-resolver.d.ts +3 -2
- package/dist/pipeline/dispatch-matched-workflow.d.ts +41 -0
- package/dist/pipeline/install-secrets-resolver.d.ts +12 -1
- package/dist/pipeline/manual-schedule.d.ts +20 -13
- package/dist/pipeline/pending-workflow-context.d.ts +1 -1
- package/dist/pipeline/process-webhook.d.ts +57 -2
- package/dist/pipeline/processor.d.ts +44 -8
- package/dist/pipeline/rerun.d.ts +12 -13
- package/dist/pipeline/resolve-sandbox-grant.d.ts +28 -0
- package/dist/pipeline/route-or-dispatch-jobs.d.ts +71 -0
- package/dist/pipeline/sandbox-allowlist-reader.d.ts +33 -0
- package/dist/policy/dashboard-write-policy.d.ts +9 -4
- package/dist/provenance/backfill-run.d.ts +1 -0
- package/dist/provenance/trust-root.d.ts +13 -0
- package/dist/providers/generic/normalizer.d.ts +1 -1
- package/dist/providers/github/auth.d.ts +1 -1
- package/dist/providers/github/changed-files.d.ts +14 -6
- package/dist/providers/github/check-status-poster.d.ts +19 -3
- package/dist/providers/github/contributor-resolver.d.ts +1 -1
- package/dist/providers/github/lock-file.d.ts +1 -1
- package/dist/providers/github/normalizer.d.ts +1 -1
- package/dist/providers/github/repo-url.d.ts +1 -1
- package/dist/providers/local/lock-file-fetcher.d.ts +1 -1
- package/dist/providers/local/normalizer.d.ts +1 -1
- package/dist/providers/local/repo-url-builder.d.ts +1 -1
- package/dist/providers/universal-git/changed-files.d.ts +8 -7
- package/dist/providers/universal-git/clone-token.d.ts +1 -1
- package/dist/providers/universal-git/config.d.ts +4 -4
- package/dist/providers/universal-git/index.d.ts +5 -1
- package/dist/providers/universal-git/lock-file.d.ts +6 -1
- package/dist/providers/universal-git/normalizer.d.ts +1 -1
- package/dist/providers/universal-git/repo-url.d.ts +1 -1
- package/dist/queue/bootstrap.d.ts +5 -0
- package/dist/queue/cleanup.d.ts +72 -9
- package/dist/queue/job-queue.d.ts +141 -14
- package/dist/queue/scheduled-job.d.ts +3 -2
- package/dist/queue/terminalize-unroutable.d.ts +53 -0
- package/dist/queue/unroutable-probe.d.ts +52 -0
- package/dist/registration/registration-index.d.ts +1 -1
- package/dist/reporting/agent-failure-category.d.ts +4 -1
- package/dist/reporting/check-run-reporter.d.ts +34 -14
- package/dist/reporting/check-run-tracking-store.d.ts +70 -8
- package/dist/reporting/execution-tracker.d.ts +156 -10
- package/dist/reporting/fs-log-storage.d.ts +31 -2
- package/dist/reporting/job-check-run-completion.d.ts +50 -0
- package/dist/reporting/log-chunk-sink.d.ts +47 -0
- package/dist/reporting/log-retention.d.ts +16 -0
- package/dist/reporting/log-storage.d.ts +64 -4
- package/dist/reporting/log-writer.d.ts +22 -7
- package/dist/reporting/peer-log-normalize.d.ts +14 -0
- package/dist/reporting/run-aggregator.d.ts +50 -33
- package/dist/reporting/s3-log-storage.d.ts +102 -8
- package/dist/routes/admin-auth.d.ts +90 -0
- package/dist/routes/admin-cluster-settings.d.ts +31 -0
- package/dist/routes/admin-events.d.ts +3 -0
- package/dist/routes/admin-orchestrator-drain.d.ts +35 -0
- package/dist/routes/admin-runs.d.ts +9 -0
- package/dist/routes/admin-sources.d.ts +7 -0
- package/dist/routes/admin-trust-policy.d.ts +49 -0
- package/dist/routes/admin.d.ts +15 -1
- package/dist/routes/github-webhook.d.ts +9 -3
- package/dist/routes/provenance-oidc.d.ts +38 -0
- package/dist/routes/verify-attestation.d.ts +21 -0
- package/dist/scaler/bare-metal-backend.d.ts +9 -2
- package/dist/scaler/config.d.ts +25 -4
- package/dist/scaler/container-backend.d.ts +9 -1
- package/dist/scaler/firecracker-backend.d.ts +29 -2
- package/dist/scaler/index.d.ts +1 -1
- package/dist/scaler/manager.d.ts +166 -8
- package/dist/scaler/pending-scale-sweeper.d.ts +35 -0
- package/dist/scaler/types.d.ts +75 -6
- package/dist/secrets/backend-registry.d.ts +32 -1
- package/dist/secrets/dashboard-encryption-key.d.ts +48 -0
- package/dist/secrets/ephemeral-keys.d.ts +16 -0
- package/dist/secrets/pg-secret-store.d.ts +10 -0
- package/dist/secrets/rbac.d.ts +5 -1
- package/dist/secrets/routing-key-scope.d.ts +6 -0
- package/dist/secrets/scope-routing.d.ts +126 -0
- package/dist/secrets/secret-resolver.d.ts +1 -14
- package/dist/secrets/token-manager.d.ts +5 -1
- package/dist/security/contributor-cache.d.ts +9 -1
- package/dist/security/trust-policy-gate.d.ts +117 -0
- package/dist/security/trust-policy-store.d.ts +78 -0
- package/dist/server.js +36074 -25052
- package/dist/sources/source-manager.d.ts +24 -0
- package/dist/stale-detector/stale-run-detector.d.ts +7 -0
- package/dist/standalone.js +35203 -25387
- package/dist/storage/filesystem.d.ts +17 -0
- package/dist/storage/key-discriminator.d.ts +20 -0
- package/dist/storage/s3.d.ts +2 -0
- package/dist/storage/types.d.ts +16 -0
- package/dist/webhook/dedup.d.ts +9 -1
- package/dist/webhook/event-log.d.ts +13 -2
- package/dist/webhook/generic-sources-listener.d.ts +4 -0
- package/dist/webhook/ingest-admission.d.ts +140 -0
- package/dist/webhook/ingest-overflow-buffer.d.ts +27 -0
- package/dist/webhook/ingest-overflow-replayer.d.ts +49 -0
- package/dist/webhook/ingest-overflow-types.d.ts +73 -0
- package/dist/webhook/loop-lag-source.d.ts +40 -0
- package/dist/webhook/observed-relay-guard.d.ts +40 -0
- package/dist/webhook/org-ingest-cap-reader.d.ts +24 -0
- package/dist/webhook/register-source-bundle.d.ts +3 -0
- package/dist/webhook/relay-reinject.d.ts +43 -0
- package/dist/worker/in-memory-job-queue.d.ts +8 -3
- package/dist/worker-core.d.ts +10 -0
- package/dist/ws/agent-api-registry.d.ts +20 -0
- package/dist/ws/agent-handler.d.ts +63 -7
- package/dist/ws/bringup-api.d.ts +99 -0
- package/dist/ws/dashboard-context-handler.d.ts +28 -10
- package/dist/ws/dashboard-run-state-handler.d.ts +31 -0
- package/dist/ws/failure-messages.d.ts +29 -0
- package/dist/ws/oidc-token-relay.d.ts +9 -0
- package/dist/ws/ownership-gate.d.ts +22 -0
- package/dist/ws/platform-client.d.ts +96 -1
- package/dist/ws/replay-chunker.d.ts +37 -0
- package/installer-image-digests.json +3 -3
- package/package.json +22 -21
- package/sbom.spdx.json +1240 -1788
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type Kysely } from 'kysely';
|
|
2
2
|
import { type LabelMatcher, type ResourceRequest } from '@kici-dev/engine';
|
|
3
3
|
import type { Database } from '../db/types.js';
|
|
4
|
+
import type { ClusterSettingsReader } from '../cluster/cluster-settings-reader.js';
|
|
4
5
|
/** Info about an expired dispatch_queue entry, returned by markExpired(). */
|
|
5
6
|
export interface ExpiredJobInfo {
|
|
6
7
|
/** dispatch_queue row ID */
|
|
@@ -9,6 +10,24 @@ export interface ExpiredJobInfo {
|
|
|
9
10
|
jobName: string;
|
|
10
11
|
/** Most recent scaler spawn-failure detail, if any was recorded. */
|
|
11
12
|
lastProvisioningError: string | null;
|
|
13
|
+
/**
|
|
14
|
+
* The job's routing selectors, carried so the expiry sweep can ask whether
|
|
15
|
+
* any agent could ever have run it. A job that expires with NO matching agent
|
|
16
|
+
* is `unroutable` (a fleet/label problem); one whose agent existed but never
|
|
17
|
+
* freed up is `timed_out_stale` (a capacity problem).
|
|
18
|
+
*/
|
|
19
|
+
runsOnLabels: string[];
|
|
20
|
+
runsOnPatterns: LabelMatcher[];
|
|
21
|
+
excludeLabels: string[];
|
|
22
|
+
excludePatterns: LabelMatcher[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A pending job as the unroutable probe sees it: the same routing facts the
|
|
26
|
+
* expiry sweep reads, plus the persisted grace clock.
|
|
27
|
+
*/
|
|
28
|
+
export interface UnroutableCandidate extends ExpiredJobInfo {
|
|
29
|
+
/** When this job first read unroutable; null while it reads routable. */
|
|
30
|
+
unroutableSince: Date | null;
|
|
12
31
|
}
|
|
13
32
|
/**
|
|
14
33
|
* Point-in-time breakdown of dispatch_queue depth used for Prometheus gauges
|
|
@@ -167,8 +186,12 @@ export interface QueuedJob {
|
|
|
167
186
|
*/
|
|
168
187
|
export declare class JobQueue {
|
|
169
188
|
private readonly db;
|
|
170
|
-
|
|
189
|
+
/** Cluster-wide fallback for queue_max_depth when cluster_settings is null. */
|
|
190
|
+
private readonly defaultMaxDepth;
|
|
171
191
|
private readonly defaultTimeoutMs;
|
|
192
|
+
private readonly clusterSettings?;
|
|
193
|
+
/** Per-job (per-org) queue-timeout resolver; falls back to defaultTimeoutMs. */
|
|
194
|
+
private readonly getQueueTimeoutMs?;
|
|
172
195
|
/** 1-second TTL cache for pending depth count to avoid extra SELECT COUNT per enqueue. */
|
|
173
196
|
private depthCache;
|
|
174
197
|
/**
|
|
@@ -181,9 +204,16 @@ export declare class JobQueue {
|
|
|
181
204
|
constructor(db: Kysely<Database>, options: {
|
|
182
205
|
maxDepth: number;
|
|
183
206
|
defaultTimeoutMs: number;
|
|
207
|
+
clusterSettings?: ClusterSettingsReader;
|
|
208
|
+
getQueueTimeoutMs?: (job: {
|
|
209
|
+
jobConfig?: Record<string, unknown>;
|
|
210
|
+
}) => Promise<number>;
|
|
184
211
|
});
|
|
185
212
|
/**
|
|
186
|
-
* Enqueue a job. Checks depth first, rejects with 'queue full' if >=
|
|
213
|
+
* Enqueue a job. Checks depth first, rejects with 'queue full' if >= the
|
|
214
|
+
* fleet-wide `queue_max_depth` (cluster_settings, falling back to the config
|
|
215
|
+
* default). The per-job timeout resolves through the per-org
|
|
216
|
+
* `queue_timeout_ms` override.
|
|
187
217
|
* @returns The generated job ID.
|
|
188
218
|
*/
|
|
189
219
|
enqueue(job: QueuedJobInput): Promise<string>;
|
|
@@ -269,17 +299,38 @@ export declare class JobQueue {
|
|
|
269
299
|
/**
|
|
270
300
|
* Insert a job directly with status='dispatched' (bypasses the queue).
|
|
271
301
|
* Used when an agent is immediately available and the job doesn't need to wait.
|
|
272
|
-
*
|
|
302
|
+
*
|
|
303
|
+
* `agentId` is the durable owner, written here for the same reason
|
|
304
|
+
* {@link markDispatched} writes it on the queue-drain path: this row is
|
|
305
|
+
* dispatched the moment it is inserted, so it never passes through
|
|
306
|
+
* `markDispatched` and would otherwise carry a NULL owner for its whole life.
|
|
307
|
+
* A coordinator that never saw the dispatch resolves ownership from this
|
|
308
|
+
* column alone, so omitting it here would make {@link hasAgentOwnedJob} answer
|
|
309
|
+
* "not owned" for every directly-dispatched job after a failover.
|
|
310
|
+
*
|
|
311
|
+
* Idempotent on the primary key: a reroute re-dispatch reuses a preassigned
|
|
312
|
+
* jobId, so a concurrent reroute from a sibling coordinator (or a duplicate
|
|
313
|
+
* delivery) may target a row this instance already wrote. ON CONFLICT (id) DO
|
|
314
|
+
* NOTHING makes that a no-op instead of a dispatch_queue_pkey error; the
|
|
315
|
+
* returned `inserted` flag tells the caller whether a fresh row was created so
|
|
316
|
+
* it can avoid double-dispatching an already-present job. The conflicting row
|
|
317
|
+
* keeps the owner the winning writer recorded.
|
|
318
|
+
*
|
|
319
|
+
* @returns The job ID and whether a new row was inserted (false = row already existed).
|
|
273
320
|
*/
|
|
274
|
-
insertDispatched(job: QueuedJobInput): Promise<
|
|
321
|
+
insertDispatched(job: QueuedJobInput, agentId: string): Promise<{
|
|
322
|
+
id: string;
|
|
323
|
+
inserted: boolean;
|
|
324
|
+
}>;
|
|
275
325
|
/**
|
|
276
|
-
* Mark a job as dispatched.
|
|
326
|
+
* Mark a job as dispatched and record the agent it went to.
|
|
277
327
|
*
|
|
278
|
-
*
|
|
279
|
-
*
|
|
280
|
-
*
|
|
328
|
+
* `agent_id` is the durable owner: the dispatcher also tracks agent-to-job
|
|
329
|
+
* mappings in memory (agentJobs Map), but that map is per-coordinator, so a
|
|
330
|
+
* coordinator that never saw the dispatch has to read the owner back from the
|
|
331
|
+
* row to answer an ownership question.
|
|
281
332
|
*/
|
|
282
|
-
markDispatched(jobId: string,
|
|
333
|
+
markDispatched(jobId: string, agentId: string): Promise<void>;
|
|
283
334
|
/**
|
|
284
335
|
* Mark a job as failed.
|
|
285
336
|
*
|
|
@@ -329,6 +380,23 @@ export declare class JobQueue {
|
|
|
329
380
|
* @returns Number of affected rows.
|
|
330
381
|
*/
|
|
331
382
|
cancelByRunId(runId: string): Promise<number>;
|
|
383
|
+
/**
|
|
384
|
+
* Delete terminal dispatch_queue rows older than `retentionDays`.
|
|
385
|
+
*
|
|
386
|
+
* `dispatch_queue` is operational dispatch state; the durable run history
|
|
387
|
+
* lives in the cold-stored execution_runs/jobs/steps tables, so a terminal
|
|
388
|
+
* ({@link DispatchQueueStatus.Completed}/{@link DispatchQueueStatus.Failed}/
|
|
389
|
+
* {@link DispatchQueueStatus.Expired}) row has no archival value once it ages
|
|
390
|
+
* out. Non-terminal rows ({@link DispatchQueueStatus.Pending}/
|
|
391
|
+
* {@link DispatchQueueStatus.Dispatched}/{@link DispatchQueueStatus.Recovering})
|
|
392
|
+
* are never pruned — a still-active run keeps every one of its rows. Both the
|
|
393
|
+
* terminal-status filter and the age cutoff must hold for a row to be deleted.
|
|
394
|
+
*
|
|
395
|
+
* `retentionDays <= 0` disables pruning (returns 0 without a query).
|
|
396
|
+
*
|
|
397
|
+
* @returns Number of rows deleted.
|
|
398
|
+
*/
|
|
399
|
+
pruneTerminalDispatchRows(retentionDays: number): Promise<number>;
|
|
332
400
|
/**
|
|
333
401
|
* Get the current number of pending jobs.
|
|
334
402
|
* Uses a 1-second TTL cache to avoid extra SELECT COUNT per enqueue.
|
|
@@ -455,11 +523,12 @@ export declare class JobQueue {
|
|
|
455
523
|
*/
|
|
456
524
|
getFullJobById(jobId: string): Promise<QueuedJob | null>;
|
|
457
525
|
/**
|
|
458
|
-
* Mark a job as dispatched only if it is still in 'recovering' state
|
|
526
|
+
* Mark a job as dispatched only if it is still in 'recovering' state, and
|
|
527
|
+
* record `agentId` as the durable owner of the reclaimed job.
|
|
459
528
|
* Used when an agent reconnects and claims a recovering job.
|
|
460
529
|
* @returns true if the update affected a row (job was still recovering).
|
|
461
530
|
*/
|
|
462
|
-
markDispatchedIfRecovering(jobId: string): Promise<boolean>;
|
|
531
|
+
markDispatchedIfRecovering(jobId: string, agentId: string): Promise<boolean>;
|
|
463
532
|
/**
|
|
464
533
|
* Get a single job by ID.
|
|
465
534
|
* Used to look up runId during recovery timer setup.
|
|
@@ -471,10 +540,11 @@ export declare class JobQueue {
|
|
|
471
540
|
} | null>;
|
|
472
541
|
/**
|
|
473
542
|
* HA-safe ownership check. Returns true if the DB shows that
|
|
474
|
-
* `agentId` previously held `jobId` according to any of:
|
|
543
|
+
* `agentId` holds or previously held `jobId` according to any of:
|
|
475
544
|
*
|
|
476
|
-
* - `status='dispatched'` AND the
|
|
477
|
-
*
|
|
545
|
+
* - `status='dispatched'` AND `agent_id = <agent>` — the live
|
|
546
|
+
* owner of an in-flight job, readable by any coordinator
|
|
547
|
+
* including one that never saw the dispatch,
|
|
478
548
|
* - `status='recovering'` AND `recovery_agent_id = <agent>` (so a
|
|
479
549
|
* replacement coord still recognises in-flight chunks), OR
|
|
480
550
|
* - the row is already terminal (`completed` / `failed` /
|
|
@@ -495,11 +565,68 @@ export declare class JobQueue {
|
|
|
495
565
|
id: string;
|
|
496
566
|
runId: string;
|
|
497
567
|
status: DispatchQueueStatus;
|
|
568
|
+
agentId: string | null;
|
|
498
569
|
}>>;
|
|
570
|
+
/**
|
|
571
|
+
* Shared builder for the non-expired pending rows, oldest-first
|
|
572
|
+
* (`created_at ASC` — the same FIFO ordering as `dequeueForLabels` /
|
|
573
|
+
* `markExpired`). Read-only: no `FOR UPDATE`, no claim. Used by both the
|
|
574
|
+
* unbounded `getPendingJobs` drain and the capped `listPending` re-drive.
|
|
575
|
+
*/
|
|
576
|
+
private pendingOldestFirstQuery;
|
|
499
577
|
/**
|
|
500
578
|
* Get all pending jobs in FIFO order (for queue drain on agent connect).
|
|
501
579
|
*/
|
|
502
580
|
getPendingJobs(): Promise<QueuedJob[]>;
|
|
581
|
+
/**
|
|
582
|
+
* Read-only oldest-first listing of pending jobs, capped at `limit`.
|
|
583
|
+
*
|
|
584
|
+
* Powers the scaler capacity-freed re-drive (`Dispatcher.retryPendingScaleRequests`):
|
|
585
|
+
* when a scaler agent frees capacity, the oldest jobs that previously got an
|
|
586
|
+
* `at-capacity` verdict are the ones re-offered to `requestScale`. Unlike
|
|
587
|
+
* `dequeueForLabels`, this neither claims nor locks rows — it is a pure read;
|
|
588
|
+
* the re-drive re-runs the normal scale path, which reserves capacity itself.
|
|
589
|
+
*/
|
|
590
|
+
listPending(limit: number): Promise<QueuedJob[]>;
|
|
591
|
+
/**
|
|
592
|
+
* Pending, non-expired jobs with the facts the unroutable probe needs:
|
|
593
|
+
* routing selectors, any recorded provisioning error, and the grace clock.
|
|
594
|
+
*
|
|
595
|
+
* Read-only — no claim, no `FOR UPDATE`; the probe never dispatches. Reuses
|
|
596
|
+
* the shared pending query so it inherits the same FIFO ordering and
|
|
597
|
+
* not-yet-expired filter the rest of the queue uses.
|
|
598
|
+
*/
|
|
599
|
+
listUnroutableCandidates(limit: number): Promise<UnroutableCandidate[]>;
|
|
600
|
+
/**
|
|
601
|
+
* Stamp the grace clock the first time a job reads unroutable.
|
|
602
|
+
*
|
|
603
|
+
* The `unroutable_since IS NULL` guard is load-bearing, not defensive: the
|
|
604
|
+
* cleanup/probe ticks are NOT leader-gated, so without it two coordinators
|
|
605
|
+
* would each re-stamp `now` on every tick, pushing the deadline outward
|
|
606
|
+
* forever and preventing the grace from ever elapsing.
|
|
607
|
+
*/
|
|
608
|
+
markUnroutableSince(id: string, at: Date): Promise<void>;
|
|
609
|
+
/** Clear the grace clock after the job reads routable again. */
|
|
610
|
+
clearUnroutableState(id: string): Promise<void>;
|
|
611
|
+
/**
|
|
612
|
+
* Claim a still-pending row for fast-fail, moving it out of the queue.
|
|
613
|
+
*
|
|
614
|
+
* Mirrors {@link markExpired}: the queue row has to leave `Pending` in the
|
|
615
|
+
* same breath the job is terminalized, and for the same two reasons.
|
|
616
|
+
* A row left pending is still dispatchable, so an agent connecting later
|
|
617
|
+
* would pick up a job whose `execution_jobs` row already reads terminal; and
|
|
618
|
+
* the probe re-lists it on every tick, re-running the whole terminalize path
|
|
619
|
+
* (and re-counting the fast-fail metric) until the queue timeout finally
|
|
620
|
+
* expires it.
|
|
621
|
+
*
|
|
622
|
+
* The `status = Pending` guard is also the concurrency arbiter — probe ticks
|
|
623
|
+
* are NOT leader-gated, so exactly one coordinator's UPDATE hits a row and
|
|
624
|
+
* the losers get `false` and move on.
|
|
625
|
+
*
|
|
626
|
+
* @returns true when this call claimed the row, false when it was already
|
|
627
|
+
* dispatched, cancelled, expired, or claimed by another coordinator.
|
|
628
|
+
*/
|
|
629
|
+
claimUnroutable(id: string): Promise<boolean>;
|
|
503
630
|
/**
|
|
504
631
|
* Convert a DB row to a QueuedJob object.
|
|
505
632
|
* Handles both auto-parsed JSONB arrays (from pg driver) and JSON strings (from tests).
|
|
@@ -25,10 +25,11 @@ import type { Database } from '../db/types.js';
|
|
|
25
25
|
*/
|
|
26
26
|
export declare const OrchestratorScheduledJobName: z.ZodEnum<{
|
|
27
27
|
cleanup: "cleanup";
|
|
28
|
-
"orphan-secret-cleanup": "orphan-secret-cleanup";
|
|
29
|
-
"token-cleanup": "token-cleanup";
|
|
30
28
|
"cold-store-archive": "cold-store-archive";
|
|
31
29
|
"cold-store-purge": "cold-store-purge";
|
|
30
|
+
"orphan-secret-cleanup": "orphan-secret-cleanup";
|
|
31
|
+
"token-cleanup": "token-cleanup";
|
|
32
|
+
"unroutable-probe": "unroutable-probe";
|
|
32
33
|
}>;
|
|
33
34
|
export type OrchestratorScheduledJobName = z.infer<typeof OrchestratorScheduledJobName>;
|
|
34
35
|
/** Access-log action for a manually triggered off-cadence tick. */
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type Kysely } from 'kysely';
|
|
2
|
+
import { ExecutionJobStatus, type LabelMatcher } from '@kici-dev/engine';
|
|
3
|
+
import type { Database } from '../db/types.js';
|
|
4
|
+
import type { ExecutionTracker } from '../reporting/execution-tracker.js';
|
|
5
|
+
import type { CheckRunReporter } from '../reporting/check-run-reporter.js';
|
|
6
|
+
import type { ExpiredJobInfo } from './job-queue.js';
|
|
7
|
+
/**
|
|
8
|
+
* Whether ANYTHING could ever run a job with these selectors — a registered
|
|
9
|
+
* agent (regardless of capacity) or a scaler backend able to spawn one.
|
|
10
|
+
*
|
|
11
|
+
* The predicate is allowed to answer "routable" conservatively: the scaler half
|
|
12
|
+
* matches exact labels only, so a pattern-only `runsOn` reads routable on a
|
|
13
|
+
* scaler-configured orchestrator. That costs precision on the status and on
|
|
14
|
+
* how quickly the job settles, never safety — a job that reads routable simply
|
|
15
|
+
* falls through to the queue-timeout backstop.
|
|
16
|
+
*/
|
|
17
|
+
export type CanRouteLabels = (requiredLabels: string[], requiredPatterns: LabelMatcher[], excludeLabels: string[], excludePatterns: LabelMatcher[]) => boolean;
|
|
18
|
+
/** The routing facts a verdict is computed from. */
|
|
19
|
+
export type JobRoutingFacts = Pick<ExpiredJobInfo, 'lastProvisioningError' | 'runsOnLabels' | 'runsOnPatterns' | 'excludeLabels' | 'excludePatterns'>;
|
|
20
|
+
/** Everything {@link terminalizeUnroutableJob} needs to settle a job. */
|
|
21
|
+
export interface TerminalizeDeps {
|
|
22
|
+
db: Kysely<Database>;
|
|
23
|
+
executionTracker: ExecutionTracker;
|
|
24
|
+
checkRunReporter?: Pick<CheckRunReporter, 'updateJobStatus'>;
|
|
25
|
+
canRouteLabels?: CanRouteLabels;
|
|
26
|
+
}
|
|
27
|
+
export declare function unroutableMessage(job: JobRoutingFacts): string;
|
|
28
|
+
/**
|
|
29
|
+
* Split the two reasons a queued job never ran: nothing in the fleet matched
|
|
30
|
+
* its `runsOn` (`unroutable` — a label/fleet problem an operator has to fix)
|
|
31
|
+
* versus something matched but never produced a usable agent
|
|
32
|
+
* (`timed_out_stale` — a capacity or provisioning problem).
|
|
33
|
+
*
|
|
34
|
+
* Shared by the unroutable probe (which asks on a short tick, gated by a grace
|
|
35
|
+
* window) and the queue-expiry sweep (which asks once at expiry, as the
|
|
36
|
+
* backstop). One verdict, two moments in time — a second copy of this logic is
|
|
37
|
+
* exactly the drift this module exists to prevent.
|
|
38
|
+
*/
|
|
39
|
+
export declare function classifyUnroutable(job: JobRoutingFacts, canRouteLabels?: CanRouteLabels): {
|
|
40
|
+
status: ExecutionJobStatus;
|
|
41
|
+
errorMessage: string;
|
|
42
|
+
unroutable: boolean;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Settle one never-dispatched job: write the terminal status locally, surface
|
|
46
|
+
* the reason at run level, forward to Platform, and resolve its check run.
|
|
47
|
+
*
|
|
48
|
+
* @returns the run id when this call actually terminalized the job (so the
|
|
49
|
+
* caller can complete the run), or null when another coordinator got there
|
|
50
|
+
* first or the job was no longer pending.
|
|
51
|
+
*/
|
|
52
|
+
export declare function terminalizeUnroutableJob(deps: TerminalizeDeps, job: ExpiredJobInfo): Promise<string | null>;
|
|
53
|
+
//# sourceMappingURL=terminalize-unroutable.d.ts.map
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type Kysely } from 'kysely';
|
|
2
|
+
import type { Database } from '../db/types.js';
|
|
3
|
+
import type { JobQueue, UnroutableCandidate } from './job-queue.js';
|
|
4
|
+
import { type CanRouteLabels } from './terminalize-unroutable.js';
|
|
5
|
+
/**
|
|
6
|
+
* The shipped default grace, mirrored from `config.ts`. Used only to derive a
|
|
7
|
+
* sane tick cadence when the env default is 0 (fast-fail disabled at startup
|
|
8
|
+
* but re-enableable live via the `unroutable_grace_ms` cluster setting).
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_UNROUTABLE_GRACE_MS = 120000;
|
|
11
|
+
/**
|
|
12
|
+
* Probe cadence, derived from the grace rather than configured separately.
|
|
13
|
+
*
|
|
14
|
+
* The tick is an implementation detail of the grace window — it only has to be
|
|
15
|
+
* fine-grained enough that the grace elapses on time — not independent policy,
|
|
16
|
+
* so it deliberately does not earn its own cluster knob.
|
|
17
|
+
*/
|
|
18
|
+
export declare function probeTickIntervalMs(graceMs: number): number;
|
|
19
|
+
/** Writes the operator-facing routing reason onto a still-queued job. */
|
|
20
|
+
export type SetRoutingReason = (runId: string, jobName: string, reason: string | null) => Promise<void>;
|
|
21
|
+
export interface UnroutableProbeDeps {
|
|
22
|
+
queue: Pick<JobQueue, 'listUnroutableCandidates' | 'markUnroutableSince' | 'clearUnroutableState' | 'claimUnroutable'>;
|
|
23
|
+
/** Live read, so an operator changing the knob takes effect without a restart. */
|
|
24
|
+
getGraceMs: () => Promise<number>;
|
|
25
|
+
canRouteLabels: CanRouteLabels;
|
|
26
|
+
setRoutingReason: SetRoutingReason;
|
|
27
|
+
terminalize: (job: UnroutableCandidate) => Promise<void>;
|
|
28
|
+
onFastFailed?: () => void;
|
|
29
|
+
/** Max rows examined per tick. */
|
|
30
|
+
batchLimit?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Write the routing reason onto a job that is still waiting to be routed.
|
|
34
|
+
*
|
|
35
|
+
* The status guard matters: the reason is a statement about a job that has not
|
|
36
|
+
* been picked up, so it must never annotate one that already started or
|
|
37
|
+
* finished between the probe's read and this write.
|
|
38
|
+
*/
|
|
39
|
+
export declare function makeRoutingReasonWriter(db: Kysely<Database>): SetRoutingReason;
|
|
40
|
+
/**
|
|
41
|
+
* Build the per-tick handler for the unroutable probe.
|
|
42
|
+
*
|
|
43
|
+
* The probe consults the SAME routability predicate the queue-expiry sweep uses
|
|
44
|
+
* — one verdict, two moments in time — but asks on a short tick instead of once
|
|
45
|
+
* an hour. On the first unroutable verdict it records the reason (so the cause
|
|
46
|
+
* is visible while the job still waits) and starts a grace clock; only once the
|
|
47
|
+
* job has been CONTINUOUSLY unroutable for the whole grace does it terminalize.
|
|
48
|
+
* A job that reads routable again has both cleared, so a scaler reload or an
|
|
49
|
+
* agent reconnect can never cost it its place in the queue.
|
|
50
|
+
*/
|
|
51
|
+
export declare function createUnroutableProbeHandler(deps: UnroutableProbeDeps): () => Promise<void>;
|
|
52
|
+
//# sourceMappingURL=unroutable-probe.d.ts.map
|
|
@@ -151,7 +151,7 @@ export declare class RegistrationIndex {
|
|
|
151
151
|
*
|
|
152
152
|
* Event type -> trigger type mapping:
|
|
153
153
|
* - 'kici_event' -> 'kici_event'
|
|
154
|
-
* - 'workflow_complete' -> 'workflow_complete' or '
|
|
154
|
+
* - 'workflow_complete' -> 'workflow_complete', 'lifecycle', or 'workflows_failed_batch'
|
|
155
155
|
* - 'job_complete' -> 'job_complete' or 'lifecycle'
|
|
156
156
|
* - 'generic_webhook' -> 'generic_webhook'
|
|
157
157
|
* - 'schedule' -> 'schedule'
|
|
@@ -13,7 +13,10 @@ export interface FailureSignals {
|
|
|
13
13
|
hasInitFailure: boolean;
|
|
14
14
|
/** The init-failure category (`InitFailureCategory`), if any. */
|
|
15
15
|
initFailureCategory: string | null;
|
|
16
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* Any job ended in an infra-class verdict that means it never really ran —
|
|
18
|
+
* `timed_out_stale` or `unroutable` — or a workflow/job timeout fired.
|
|
19
|
+
*/
|
|
17
20
|
timedOut: boolean;
|
|
18
21
|
/** Any step recorded a non-zero exit code. */
|
|
19
22
|
anyStepNonZeroExit: boolean;
|
|
@@ -30,7 +30,7 @@ import type { ProviderRegistry } from '../provider-registry.js';
|
|
|
30
30
|
import type { StepLogBuffer } from './step-log-buffer.js';
|
|
31
31
|
import { type SourceLocationData } from './check-run-summary.js';
|
|
32
32
|
import type { CheckRunTrackingStore } from './check-run-tracking-store.js';
|
|
33
|
-
import {
|
|
33
|
+
import { type TerminalJobStatus } from '@kici-dev/engine';
|
|
34
34
|
/**
|
|
35
35
|
* Dependencies for the CheckRunReporter.
|
|
36
36
|
*/
|
|
@@ -122,7 +122,7 @@ interface SetBuildCompleteOptions {
|
|
|
122
122
|
repo: string;
|
|
123
123
|
sha: string;
|
|
124
124
|
workflowName: string;
|
|
125
|
-
status:
|
|
125
|
+
status: TerminalJobStatus;
|
|
126
126
|
installationId?: number;
|
|
127
127
|
/** Routing key for per-app credential lookup (e.g., "github:12345"). */
|
|
128
128
|
routingKey?: string;
|
|
@@ -142,7 +142,7 @@ interface UpdateJobStatusOptions {
|
|
|
142
142
|
sha: string;
|
|
143
143
|
workflowName: string;
|
|
144
144
|
jobName: string;
|
|
145
|
-
state:
|
|
145
|
+
state: TerminalJobStatus;
|
|
146
146
|
installationId?: number;
|
|
147
147
|
/** Routing key for per-app credential lookup (e.g., "github:12345"). */
|
|
148
148
|
routingKey?: string;
|
|
@@ -167,7 +167,7 @@ interface UpdateWorkflowStatusOptions {
|
|
|
167
167
|
repo: string;
|
|
168
168
|
sha: string;
|
|
169
169
|
workflowName: string;
|
|
170
|
-
overallStatus:
|
|
170
|
+
overallStatus: TerminalJobStatus;
|
|
171
171
|
installationId?: number;
|
|
172
172
|
/** Routing key for per-app credential lookup (e.g., "github:12345"). */
|
|
173
173
|
routingKey?: string;
|
|
@@ -238,6 +238,19 @@ export declare class CheckRunReporter {
|
|
|
238
238
|
private readonly progressTimers;
|
|
239
239
|
/** L1 cache: first in-progress sent flag (synced to `check_run_tracking.in_progress_sent_at`). */
|
|
240
240
|
private readonly inProgressSent;
|
|
241
|
+
/**
|
|
242
|
+
* Keys whose job check run has already been completed.
|
|
243
|
+
*
|
|
244
|
+
* Makes the check run's status monotonic: once a `completed` update is
|
|
245
|
+
* issued, no later step-progress update may push it back to `in_progress`.
|
|
246
|
+
* Cancelling the pending debounce timer at completion time is not sufficient
|
|
247
|
+
* on its own — a step status that arrives after the completion schedules a
|
|
248
|
+
* FRESH timer, which then fires and leaves the check run showing
|
|
249
|
+
* `status: in_progress` with a terminal `conclusion` already attached. That
|
|
250
|
+
* is the permanently-unresolved state check-run completion exists to prevent,
|
|
251
|
+
* so the guard is on the write itself rather than on the timer.
|
|
252
|
+
*/
|
|
253
|
+
private readonly terminalSent;
|
|
241
254
|
/**
|
|
242
255
|
* L1 cache: runId → set of check-run composite keys. Synced to the
|
|
243
256
|
* indexed `check_run_tracking.run_id` column so a replacement coord can
|
|
@@ -334,21 +347,28 @@ export declare class CheckRunReporter {
|
|
|
334
347
|
*/
|
|
335
348
|
setBuildComplete(opts: SetBuildCompleteOptions): void;
|
|
336
349
|
/**
|
|
337
|
-
* Clean up step-progress entries
|
|
338
|
-
*
|
|
350
|
+
* Clean up step-progress entries and debounce timers for a completed run.
|
|
351
|
+
* Called when the execution tracker prunes the run.
|
|
339
352
|
*
|
|
340
|
-
* In-memory
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
*
|
|
353
|
+
* In-memory only. Database rows are owned by the retention sweep in
|
|
354
|
+
* `queue/cleanup.ts`, which deletes on inactivity age rather than on run
|
|
355
|
+
* completion. Deleting here would strand a late terminal update: a check-run
|
|
356
|
+
* status PATCH that arrives after the prune resolves its check-run ID by
|
|
357
|
+
* loading through to this row, and a deleted row makes that lookup fail.
|
|
344
358
|
*/
|
|
345
359
|
cleanupRun(runId: string): void;
|
|
346
360
|
/**
|
|
347
|
-
*
|
|
348
|
-
*
|
|
349
|
-
* runIdToKeys reverse map is populated for any future cleanupRun calls
|
|
350
|
-
* without requiring a DB round-trip per cleanup. If no store is wired,
|
|
361
|
+
* Mark the reporter as DB-backed after a leader switch (or any boot-time
|
|
362
|
+
* recovery). Called once on coord become-leader. If no store is wired,
|
|
351
363
|
* this is a no-op.
|
|
364
|
+
*
|
|
365
|
+
* Nothing is hydrated up front — the table can be large across many shas —
|
|
366
|
+
* so check-run IDs load through on demand inside `resolveCheckRunId`. The
|
|
367
|
+
* `runIdToKeys` reverse map is rebuilt only from this coord's own writes,
|
|
368
|
+
* so a run whose keys all predate the switch leaves `cleanupRun` nothing to
|
|
369
|
+
* evict. That is harmless: the L1 caches it clears are equally empty on a
|
|
370
|
+
* fresh coord, and the DB rows belong to the retention sweep rather than to
|
|
371
|
+
* run prune.
|
|
352
372
|
*/
|
|
353
373
|
recoverState(): Promise<void>;
|
|
354
374
|
/** Track a check run key associated with a runId for later cleanup. */
|
|
@@ -29,7 +29,16 @@ export interface CheckRunTrackingState {
|
|
|
29
29
|
stepProgress: StepProgressEntry[];
|
|
30
30
|
/** Timestamp the first running-step transition was sent to GitHub. */
|
|
31
31
|
inProgressSentAt?: Date;
|
|
32
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Timestamp the terminal (`completed`) update was accepted by the provider.
|
|
34
|
+
* Undefined means we have no record of sending it — not proof it failed.
|
|
35
|
+
*/
|
|
36
|
+
terminalSentAt?: Date;
|
|
37
|
+
/**
|
|
38
|
+
* KiCI run this check-run belongs to. Written at create time so the row
|
|
39
|
+
* records its owning run; it is an attribution/lookup key, not a retention
|
|
40
|
+
* key — the sweep prunes on `updated_at` age alone.
|
|
41
|
+
*/
|
|
33
42
|
runId?: string;
|
|
34
43
|
/** Last persisted update time; powers debounce-after-failover recovery. */
|
|
35
44
|
updatedAt?: Date;
|
|
@@ -64,8 +73,13 @@ export declare class CheckRunTrackingStore {
|
|
|
64
73
|
* Performed as an upsert so a re-issued setPending after a coord
|
|
65
74
|
* failover replaces the prior ID rather than silently leaving a row
|
|
66
75
|
* mismatched with the GitHub-side state.
|
|
76
|
+
*
|
|
77
|
+
* `runId` is written alongside so the row records which run owns it from
|
|
78
|
+
* the moment it is created. A row created without it carries a NULL
|
|
79
|
+
* `run_id`, which makes `listKeysByRunId` under-report and leaves the
|
|
80
|
+
* column useless to an operator asking which run posted a given check.
|
|
67
81
|
*/
|
|
68
|
-
setCheckRunId(key: CheckRunTrackingKey, checkRunId: number): Promise<void>;
|
|
82
|
+
setCheckRunId(key: CheckRunTrackingKey, checkRunId: number, runId?: string): Promise<void>;
|
|
69
83
|
/**
|
|
70
84
|
* Lookup the check-run ID for a key. Returns undefined if no row exists
|
|
71
85
|
* yet OR the row exists but the GitHub create has not finished
|
|
@@ -93,6 +107,14 @@ export declare class CheckRunTrackingStore {
|
|
|
93
107
|
* cluster-wide.
|
|
94
108
|
*/
|
|
95
109
|
markInProgressSent(key: CheckRunTrackingKey, runId?: string): Promise<void>;
|
|
110
|
+
/**
|
|
111
|
+
* Stamp that the terminal (`completed`) provider update was sent.
|
|
112
|
+
*
|
|
113
|
+
* Mirrors `markInProgressSent`. Best-effort like every write on this table —
|
|
114
|
+
* the caller swallows failures, because a tracking write must never break
|
|
115
|
+
* check-run reporting — so a null column is "no record", not "never sent".
|
|
116
|
+
*/
|
|
117
|
+
markTerminalSent(key: CheckRunTrackingKey, runId?: string): Promise<void>;
|
|
96
118
|
/**
|
|
97
119
|
* Get the full state snapshot for a key. Used by the L1 cache to
|
|
98
120
|
* hydrate on miss and by tests to verify the on-disk layout. Returns
|
|
@@ -104,17 +126,56 @@ export declare class CheckRunTrackingStore {
|
|
|
104
126
|
*/
|
|
105
127
|
deleteRow(key: CheckRunTrackingKey): Promise<boolean>;
|
|
106
128
|
/**
|
|
107
|
-
* List every key currently tracked for a runId
|
|
108
|
-
*
|
|
109
|
-
*
|
|
129
|
+
* List every key currently tracked for a runId — the runId → keys reverse
|
|
130
|
+
* index that `CheckRunReporter` otherwise holds only in memory, so a
|
|
131
|
+
* replacement coord that never saw the run can still recover it. Index
|
|
132
|
+
* `idx_check_run_tracking_run_id` keeps this O(matches).
|
|
133
|
+
*
|
|
134
|
+
* No caller in tree: run-prune stopped consulting the store once row
|
|
135
|
+
* lifetime moved to {@link pruneStale}. Kept as the read half of the
|
|
136
|
+
* `run_id` column, beside {@link deleteByRunId}.
|
|
110
137
|
*/
|
|
111
138
|
listKeysByRunId(runId: string): Promise<CheckRunTrackingKey[]>;
|
|
112
139
|
/**
|
|
113
|
-
* Delete every row for a runId.
|
|
114
|
-
*
|
|
115
|
-
*
|
|
140
|
+
* Delete every row for a runId.
|
|
141
|
+
*
|
|
142
|
+
* Not on the run-prune path: `cleanupRun` evicts only its in-memory state,
|
|
143
|
+
* because a row deleted at prune time strands a late terminal PATCH that
|
|
144
|
+
* still has to resolve its check-run ID. Routine reclamation is
|
|
145
|
+
* {@link pruneStale}. This remains as the targeted escape hatch for
|
|
146
|
+
* discarding one run's rows deliberately.
|
|
116
147
|
*/
|
|
117
148
|
deleteByRunId(runId: string): Promise<number>;
|
|
149
|
+
/**
|
|
150
|
+
* Delete every row untouched for longer than `retentionDays`, and return
|
|
151
|
+
* how many were removed. `retentionDays <= 0` disables the sweep, matching
|
|
152
|
+
* the `JobQueue.pruneTerminalDispatchRows` convention.
|
|
153
|
+
*
|
|
154
|
+
* `updated_at` is the staleness signal because the table carries no status
|
|
155
|
+
* column, and the rows that most need reaping are precisely the ones with no
|
|
156
|
+
* `run_id` to join on — so the predicate is age alone, deliberately
|
|
157
|
+
* unfiltered by `run_id`. Every upsert bumps `updated_at`, so a run that is
|
|
158
|
+
* still emitting check-run traffic keeps its rows fresh; a workflow-level
|
|
159
|
+
* row, written once at create, ages from creation.
|
|
160
|
+
*
|
|
161
|
+
* Inactivity age rather than run completion is what keeps a reader safe: a
|
|
162
|
+
* row a diagnostic is polling for cannot disappear underneath it, because
|
|
163
|
+
* the window is days and the row is only removed once nothing has touched
|
|
164
|
+
* it for that long.
|
|
165
|
+
*
|
|
166
|
+
* The bound this trades for that safety: age is measured on check-run
|
|
167
|
+
* writes, not on run liveness, so a run that stays live while emitting no
|
|
168
|
+
* check-run traffic for longer than the window — a run parked on a manual
|
|
169
|
+
* approval gate, whose hold statuses go through `CheckStatusPoster` and
|
|
170
|
+
* never touch this table — has its rows swept while it is still running.
|
|
171
|
+
* The reporter's L1 cache still holds the ID, so its terminal update lands
|
|
172
|
+
* anyway on a coord that stayed up; it takes a restart or failover across
|
|
173
|
+
* that window to leave the update with no row to load through and no
|
|
174
|
+
* check-run ID to resolve.
|
|
175
|
+
*
|
|
176
|
+
* Called from the hourly cleanup tick.
|
|
177
|
+
*/
|
|
178
|
+
pruneStale(retentionDays: number): Promise<number>;
|
|
118
179
|
private selectRow;
|
|
119
180
|
private upsertRow;
|
|
120
181
|
}
|
|
@@ -127,6 +188,7 @@ export declare function rowToState(row: {
|
|
|
127
188
|
build_creation_state: string | null;
|
|
128
189
|
step_progress_json: unknown;
|
|
129
190
|
in_progress_sent_at: Date | null;
|
|
191
|
+
terminal_sent_at: Date | null;
|
|
130
192
|
run_id: string | null;
|
|
131
193
|
updated_at: Date;
|
|
132
194
|
}): CheckRunTrackingState;
|