@kici-dev/orchestrator 0.6.0 → 0.7.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/agent/dispatcher.d.ts +10 -1
- package/dist/agent/host-roster.d.ts +8 -3
- package/dist/agent/registry.d.ts +60 -5
- package/dist/app.d.ts +10 -5
- package/dist/cache/dep-cache.d.ts +14 -6
- package/dist/cache/global-eval-round-cache.d.ts +1 -1
- package/dist/cache/index.d.ts +1 -1
- package/dist/cache/source-cache.d.ts +92 -15
- package/dist/cancel/cancel-run.d.ts +20 -2
- package/dist/cancel/sweep-stuck-cancelling.d.ts +30 -0
- package/dist/cli/api-client.d.ts +10 -0
- package/dist/cli/commands/agent-service/logs.d.ts +1 -1
- package/dist/cli/commands/agent-service/restart.d.ts +1 -1
- package/dist/cli/commands/agent-service/start.d.ts +1 -1
- package/dist/cli/commands/agent-service/status.d.ts +1 -1
- package/dist/cli/commands/agent-service/stop.d.ts +1 -1
- package/dist/cli/commands/agent-service/uninstall.d.ts +1 -1
- package/dist/cli/commands/agent.d.ts +25 -0
- package/dist/cli/commands/config.d.ts +16 -0
- package/dist/cli/commands/db-backup.d.ts +46 -0
- package/dist/cli/commands/held-run.d.ts +9 -0
- package/dist/cli/commands/orchestrator-service/drain.d.ts +2 -19
- package/dist/cli/commands/orchestrator-service/index.d.ts +9 -1
- package/dist/cli/commands/orchestrator-service/install-env.d.ts +43 -2
- package/dist/cli/commands/orchestrator-service/logs.d.ts +1 -1
- package/dist/cli/commands/orchestrator-service/restart.d.ts +1 -1
- package/dist/cli/commands/orchestrator-service/start.d.ts +1 -1
- package/dist/cli/commands/orchestrator-service/status.d.ts +17 -1
- package/dist/cli/commands/orchestrator-service/stop.d.ts +1 -1
- package/dist/cli/commands/orchestrator-service/uninstall.d.ts +1 -1
- package/dist/cli/commands/orchestrator-service/upgrade.d.ts +2 -1
- package/dist/cli/commands/rotate.d.ts +1 -1
- package/dist/cli/commands/shared/env-file-mode.d.ts +16 -0
- package/dist/cli/commands/shared/upgrade-hooks.d.ts +32 -0
- package/dist/cli/commands/shared/upgrade-safety.d.ts +81 -0
- package/dist/cli/commands/shared/versioned-upgrade.d.ts +67 -12
- package/dist/cli/commands/source.d.ts +1 -0
- package/dist/cli/commands/token.d.ts +4 -0
- package/dist/cli/commands/trust-policy.d.ts +57 -1
- package/dist/cli/join.d.ts +1 -1
- package/dist/cli/service/backup-timer.d.ts +108 -0
- package/dist/cli/service/compose-path.d.ts +11 -0
- package/dist/cli/service/compose.d.ts +22 -0
- package/dist/cli/service/deploy-env.d.ts +10 -11
- package/dist/cli/service/env-assignment.d.ts +24 -0
- package/dist/cli/service/index.d.ts +2 -2
- package/dist/cli/service/instance/resolve.d.ts +71 -7
- package/dist/cli/service/instance/types.d.ts +15 -0
- package/dist/cli/service/launchd.d.ts +7 -0
- package/dist/cli/service/systemd.d.ts +1 -0
- package/dist/cli/service/types.d.ts +36 -0
- package/dist/cli/service/windows.d.ts +16 -0
- package/dist/cli/wizard/orchestrator-wizard.d.ts +12 -3
- package/dist/cli/wizard/prompts.d.ts +7 -0
- package/dist/cli.js +12525 -9298
- package/dist/cluster/cluster-settings-reader.d.ts +2 -2
- package/dist/cluster/coordinator.d.ts +11 -0
- package/dist/cluster/instance-heartbeat.d.ts +96 -0
- package/dist/cluster/join-client.d.ts +55 -5
- package/dist/cluster/join-handler.d.ts +1 -0
- package/dist/cluster/orphan-recovery.d.ts +16 -0
- package/dist/cluster/peer-registry.d.ts +10 -0
- package/dist/concurrency/dispatch-next-queued.d.ts +1 -13
- package/dist/concurrency/index.d.ts +1 -2
- package/dist/concurrency/queue-manager.d.ts +63 -18
- package/dist/config/env-overlay.d.ts +3 -2
- package/dist/config.d.ts +24 -0
- package/dist/contexts/release-queued-holds.d.ts +23 -1
- package/dist/dashboard/attestation-filters.d.ts +2 -0
- package/dist/dashboard/handler.d.ts +22 -2
- package/dist/db/deferred-indexes.d.ts +72 -0
- package/dist/db/migration-test-harness.d.ts +22 -0
- package/dist/db/migrations/131_execution_jobs_git_credentials.d.ts +30 -0
- package/dist/db/migrations/132_execution_runs_trigger_event.d.ts +23 -0
- package/dist/db/migrations/133_dispatch_queue_source_tar_digest.d.ts +23 -0
- package/dist/db/migrations/134_dispatch_queue_ownership.d.ts +4 -0
- package/dist/db/migrations/135_cluster_settings_retention_days.d.ts +4 -0
- package/dist/db/migrations/136_master_key_wrapped_tables_key_version.d.ts +4 -0
- package/dist/db/migrations/137_execution_runs_pr_head_context.d.ts +4 -0
- package/dist/db/migrations/138_execution_runs_subject_trigger_event.d.ts +4 -0
- package/dist/db/migrations/139_admin_token_subject.d.ts +4 -0
- package/dist/db/migrations/140_dispatch_queue_canonical_labels.d.ts +54 -0
- package/dist/db/migrations/141_event_log_shed.d.ts +15 -0
- package/dist/db/migrator.d.ts +47 -0
- package/dist/db/notify-listener.d.ts +60 -0
- package/dist/db/synthetic-job-ids.d.ts +24 -0
- package/dist/db/types.d.ts +169 -4
- package/dist/deployment/deployment-identity.d.ts +31 -1
- package/dist/diagnostics/checks/index.d.ts +2 -1
- package/dist/diagnostics/checks/retention.d.ts +24 -0
- package/dist/diagnostics/types.d.ts +7 -0
- package/dist/events/event-router.d.ts +1 -1
- package/dist/fault-injection-types.d.ts +53 -0
- package/dist/firecracker/host-network.d.ts +63 -8
- package/dist/git/credential-broker.d.ts +35 -2
- package/dist/git/inherited-secret.d.ts +7 -2
- package/dist/git/job-context.d.ts +7 -4
- package/dist/helpers/secure-write.d.ts +35 -0
- package/dist/index.js +196 -67
- package/dist/metrics/prometheus.d.ts +116 -1
- package/dist/oidc/db-signer.d.ts +27 -5
- package/dist/oidc/id-token-claims.d.ts +33 -2
- package/dist/oidc/oidc-mint-registration.d.ts +6 -0
- package/dist/oidc/orchestrator-mint.d.ts +8 -0
- package/dist/oidc/reconcile-signing-key.d.ts +37 -0
- package/dist/orchestrator-core.d.ts +9 -3
- package/dist/pipeline/decorating-secret-resolver.d.ts +1 -1
- package/dist/pipeline/dispatch-matched-workflow.d.ts +65 -14
- package/dist/pipeline/manual-schedule.d.ts +1 -0
- package/dist/pipeline/process-webhook.d.ts +20 -2
- package/dist/pipeline/route-or-dispatch-jobs.d.ts +7 -0
- package/dist/pipeline/run-event-context.d.ts +39 -0
- package/dist/policy/dashboard-write-policy-listener.d.ts +1 -1
- package/dist/policy/dashboard-write-policy.d.ts +47 -1
- package/dist/provenance/dispatch-context.d.ts +46 -0
- package/dist/provenance/verify-deferred-capture.d.ts +39 -0
- package/dist/providers/github/auth.d.ts +9 -0
- package/dist/providers/github/deliveries.d.ts +118 -0
- package/dist/providers/universal-git/config.d.ts +1 -1
- package/dist/queue/cleanup.d.ts +13 -0
- package/dist/queue/job-queue.d.ts +162 -14
- package/dist/queue/retention.d.ts +105 -0
- package/dist/reporting/execution-tracker.d.ts +87 -36
- package/dist/routes/admin-db.d.ts +5 -0
- package/dist/routes/admin-events.d.ts +13 -0
- package/dist/routes/admin-held-runs.d.ts +11 -1
- package/dist/routes/admin-org-settings.d.ts +9 -0
- package/dist/routes/admin-runs.d.ts +7 -4
- package/dist/routes/admin-sources.d.ts +15 -0
- package/dist/routes/admin-trust-policy.d.ts +11 -0
- package/dist/routes/admin.d.ts +25 -0
- package/dist/scaler/backend-factory.d.ts +16 -0
- package/dist/scaler/bare-metal-backend.d.ts +22 -4
- package/dist/scaler/config.d.ts +6 -3
- package/dist/scaler/container-backend.d.ts +102 -3
- package/dist/scaler/container-hostconfig.d.ts +60 -0
- package/dist/scaler/file-tail.d.ts +25 -2
- package/dist/scaler/firecracker-api.d.ts +9 -1
- package/dist/scaler/firecracker-backend.d.ts +135 -2
- package/dist/scaler/host-access.d.ts +59 -0
- package/dist/scaler/index.d.ts +1 -0
- package/dist/scaler/manager.d.ts +33 -0
- package/dist/scaler/scaler-state-store.d.ts +6 -0
- package/dist/scaler/types.d.ts +5 -7
- package/dist/secrets/config.d.ts +48 -0
- package/dist/secrets/dashboard-encryption-key.d.ts +19 -0
- package/dist/secrets/ephemeral-keys.d.ts +9 -3
- package/dist/secrets/index.d.ts +3 -1
- package/dist/secrets/job-secret-gate.d.ts +76 -0
- package/dist/secrets/master-key-rotation.d.ts +65 -0
- package/dist/secrets/secret-output-crypto.d.ts +17 -0
- package/dist/secrets/secret-resolver.d.ts +23 -6
- package/dist/secrets/source-credentials.d.ts +1 -1
- package/dist/secrets/token-manager.d.ts +4 -1
- package/dist/security/reduced-privilege-note.d.ts +5 -0
- package/dist/security/trust-policy-gate.d.ts +70 -6
- package/dist/security/trust-tier.d.ts +31 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +10674 -5283
- package/dist/sources/source-manager.d.ts +1 -1
- package/dist/stale-detector/stale-dispatch-candidates.d.ts +43 -0
- package/dist/standalone.js +9258 -4122
- package/dist/storage/loopback-guard.d.ts +53 -6
- package/dist/webhook/event-log.d.ts +14 -1
- package/dist/webhook/generic-sources-listener.d.ts +1 -1
- package/dist/webhook/ingest-admission.d.ts +24 -0
- package/dist/webhook/ingest-overflow-replayer.d.ts +78 -14
- package/dist/webhook/ingest-overflow-types.d.ts +13 -1
- package/dist/webhook/register-source-bundle.d.ts +23 -0
- package/dist/webhook/relay-reinject.d.ts +11 -12
- package/dist/webhook/shed-breadcrumb.d.ts +15 -0
- package/dist/ws/git-credential-relay.d.ts +41 -12
- package/dist/ws/platform-client.d.ts +28 -5
- package/installer-image-digests.json +3 -3
- package/package.json +4 -4
- package/sbom.spdx.json +53 -53
- package/dist/concurrency/group-tracker.d.ts +0 -51
- package/dist/scaler/nftables.d.ts +0 -111
|
@@ -3,7 +3,7 @@ import type { Database } from '../db/types.js';
|
|
|
3
3
|
/** Numeric columns on cluster_settings readable via {@link ClusterSettingsReader}. */
|
|
4
4
|
export type ClusterNumberColumn = 'max_github_payload_bytes' | 'event_log_max_payload_bytes' | 'lock_file_max_bytes' | 'webhook_dedup_ttl_ms'
|
|
5
5
|
/** @deprecated Readable, but no call site reads it. Removed at v1.0.0. */
|
|
6
|
-
| 'contributor_cache_ttl_ms' | 'event_router_event_ttl_seconds' | 'event_router_max_dispatch_attempts' | 'queue_max_depth' | 'reroute_flap_grace_ms' | 'max_fanout_hosts' | 'event_router_rate_limit_per_workflow_per_minute' | 'cache_max_tarball_bytes' | 'cache_ttl_days' | 'lockfile_cache_max' | 'lockfile_cache_max_bytes' | 'lockfile_cache_ttl_ms' | 'content_cache_max' | 'content_cache_max_bytes' | 'content_cache_ttl_ms' | 'global_eval_round_timeout_ms' | 'global_eval_candidate_timeout_ms' | 'global_eval_cache_max' | 'global_eval_wait_timeout_ms' | 'check_run_tracking_ttl_days' | 'concurrency_wait_timeout_ms' | 'agent_token_ttl_ms' | 'ownership_db_check_timeout_ms' | 'unroutable_grace_ms' | 'ingest_overflow_claim_timeout_ms' | 'scaler_reap_interval_ms' | 'scaler_reap_stranded_timeout_ms' | 'scaler_reap_reattempt_interval_ms' | 'scaler_claim_retention_ms' | 'scaler_provision_backoff_base_ms' | 'scaler_provision_backoff_max_ms' | 'scaler_provision_max_consecutive_failures';
|
|
6
|
+
| 'contributor_cache_ttl_ms' | 'event_router_event_ttl_seconds' | 'event_router_max_dispatch_attempts' | 'queue_max_depth' | 'reroute_flap_grace_ms' | 'max_fanout_hosts' | 'event_router_rate_limit_per_workflow_per_minute' | 'cache_max_tarball_bytes' | 'cache_ttl_days' | 'lockfile_cache_max' | 'lockfile_cache_max_bytes' | 'lockfile_cache_ttl_ms' | 'content_cache_max' | 'content_cache_max_bytes' | 'content_cache_ttl_ms' | 'global_eval_round_timeout_ms' | 'global_eval_candidate_timeout_ms' | 'global_eval_cache_max' | 'global_eval_wait_timeout_ms' | 'check_run_tracking_ttl_days' | 'run_retention_days' | 'audit_retention_days' | 'provenance_retention_days' | 'held_run_retention_days' | 'concurrency_wait_timeout_ms' | 'agent_token_ttl_ms' | 'ownership_db_check_timeout_ms' | 'unroutable_grace_ms' | 'ingest_overflow_claim_timeout_ms' | 'scaler_reap_interval_ms' | 'scaler_reap_stranded_timeout_ms' | 'scaler_reap_reattempt_interval_ms' | 'scaler_claim_retention_ms' | 'scaler_provision_backoff_base_ms' | 'scaler_provision_backoff_max_ms' | 'scaler_provision_max_consecutive_failures';
|
|
7
7
|
/** Text columns on cluster_settings readable via {@link ClusterSettingsReader}. */
|
|
8
8
|
export type ClusterStringColumn = 'dashboard_verified_issuer';
|
|
9
9
|
/** Boolean columns on cluster_settings readable via {@link ClusterSettingsReader}. */
|
|
@@ -40,7 +40,7 @@ export declare const CACHE_MAX_ENTRIES_CEILING = 100000;
|
|
|
40
40
|
*
|
|
41
41
|
* A value that is not a usable positive count (NaN, non-finite, below 1) falls
|
|
42
42
|
* back to the configured default rather than clamping to 1: a 1-entry cache
|
|
43
|
-
* thrashes silently, which is harder to diagnose than
|
|
43
|
+
* thrashes silently, which is harder to diagnose than ignoring garbage.
|
|
44
44
|
* The fallback is floored and bounded by the ceiling on the same path as the
|
|
45
45
|
* stored value, so neither a fractional nor an above-ceiling configured default
|
|
46
46
|
* can reach the LRU constructor as a non-integer or unclamped max — the
|
|
@@ -47,6 +47,7 @@ export interface JobToRoute {
|
|
|
47
47
|
sha: string;
|
|
48
48
|
sourceTarUrl?: string;
|
|
49
49
|
sourceTarHash?: string;
|
|
50
|
+
sourceTarDigest?: string;
|
|
50
51
|
depsUrl?: string;
|
|
51
52
|
depsHash?: string;
|
|
52
53
|
/** Labels that the dispatched agent must NOT have. */
|
|
@@ -325,6 +326,16 @@ export declare class RunCoordinator {
|
|
|
325
326
|
private handleRerouteSpawnTimeout;
|
|
326
327
|
/** Best-effort cancel a single job on a peer (double-execution guard). */
|
|
327
328
|
private cancelPeerJob;
|
|
329
|
+
/**
|
|
330
|
+
* Forward `job.cancel` for ONE job to the coordinator that holds its agent's
|
|
331
|
+
* socket, reporting whether the message left this process.
|
|
332
|
+
*
|
|
333
|
+
* The run-cancel path needs this for a job this coordinator never routed:
|
|
334
|
+
* the Platform picks any pool member to receive `run.cancel.request`, and only
|
|
335
|
+
* the coordinator holding the agent's socket can put a cancel frame on it.
|
|
336
|
+
* {@link RunCoordinator.cancelRun} covers rerouted jobs and is unchanged.
|
|
337
|
+
*/
|
|
338
|
+
cancelJobOnPeer(peerId: string, runId: string, jobId: string, reason: string): boolean;
|
|
328
339
|
/**
|
|
329
340
|
* Local fallback for a re-dispatch: dispatch the job on this coordinator under
|
|
330
341
|
* the existing jobId. Returns true when the local dispatcher accepts it.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { Kysely } from 'kysely';
|
|
2
|
+
import type { Database } from '../db/types.js';
|
|
3
|
+
/** Default interval between `cluster_instances` heartbeat writes. */
|
|
4
|
+
export declare const DEFAULT_INSTANCE_HEARTBEAT_MS = 10000;
|
|
5
|
+
/**
|
|
6
|
+
* How many missed ticks a coordinator gets before it reads as dead. Six ticks
|
|
7
|
+
* (60 s at the default interval) is wide enough that a GC pause, a slow DB or a
|
|
8
|
+
* brief network stall does not evict a healthy coordinator — the cost of a
|
|
9
|
+
* false "dead" verdict is another coordinator recovering jobs it is watching.
|
|
10
|
+
*/
|
|
11
|
+
export declare const HEARTBEAT_MISSES_BEFORE_DEAD = 6;
|
|
12
|
+
/**
|
|
13
|
+
* The dispatcher's recovery grace period at the default config: twice
|
|
14
|
+
* `agentMaxReconnectDelayMs` (60 s). Used as the fallback floor when a caller
|
|
15
|
+
* has no configured grace period to hand in.
|
|
16
|
+
*/
|
|
17
|
+
export declare const DEFAULT_RECOVERY_GRACE_MS = 120000;
|
|
18
|
+
/**
|
|
19
|
+
* The window inside which a `cluster_instances` row counts as live.
|
|
20
|
+
*
|
|
21
|
+
* Deliberately the larger of the recovery grace period and six heartbeat ticks:
|
|
22
|
+
* the ownership predicate must never call a coordinator dead sooner than the
|
|
23
|
+
* recovery machinery would have given it to reconnect.
|
|
24
|
+
*/
|
|
25
|
+
export declare function instanceLivenessGraceMs(gracePeriodMs: number, heartbeatMs?: number): number;
|
|
26
|
+
export interface InstanceHeartbeatOptions {
|
|
27
|
+
db: Kysely<Database>;
|
|
28
|
+
instanceId: string;
|
|
29
|
+
/** Interval between writes. Defaults to {@link DEFAULT_INSTANCE_HEARTBEAT_MS}. */
|
|
30
|
+
intervalMs?: number;
|
|
31
|
+
/** Orchestrator version, recorded for operator visibility. */
|
|
32
|
+
version?: string;
|
|
33
|
+
/** Reads the current Raft role, when the node runs Raft. */
|
|
34
|
+
getRole?: () => string | null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Writes this coordinator's liveness into `cluster_instances` on a fixed tick.
|
|
38
|
+
*
|
|
39
|
+
* Every ownership predicate in the dispatch plane asks "is the coordinator that
|
|
40
|
+
* owns this row still alive?", and the answer has to come from the database.
|
|
41
|
+
* The in-memory peer registry cannot answer it: it is empty at exactly the
|
|
42
|
+
* moment startup recovery runs, because a freshly booted process has not
|
|
43
|
+
* handshaken with any peer yet, so it reads every live sibling as dead — which
|
|
44
|
+
* is the boot-time bug the predicate exists to fix. Raft membership is worse:
|
|
45
|
+
* a partitioned coordinator self-elects and reads the other half as gone.
|
|
46
|
+
*
|
|
47
|
+
* A DB heartbeat needs no peer connectivity, so it behaves the same in a
|
|
48
|
+
* Raft cluster, a plain multi-coordinator deployment and a standalone one.
|
|
49
|
+
* `host_roster` already derives agent liveness this way; this is the same
|
|
50
|
+
* mechanism pointed at coordinators.
|
|
51
|
+
*/
|
|
52
|
+
export declare class InstanceHeartbeat {
|
|
53
|
+
private readonly db;
|
|
54
|
+
private readonly instanceId;
|
|
55
|
+
private readonly intervalMs;
|
|
56
|
+
private readonly version;
|
|
57
|
+
private readonly getRole?;
|
|
58
|
+
private timer;
|
|
59
|
+
constructor(opts: InstanceHeartbeatOptions);
|
|
60
|
+
/**
|
|
61
|
+
* Write one heartbeat immediately, then every `intervalMs`.
|
|
62
|
+
*
|
|
63
|
+
* The immediate write matters: startup recovery runs moments after boot and
|
|
64
|
+
* reads this table, so a coordinator that had not yet written a row would be
|
|
65
|
+
* invisible to its own siblings' predicates.
|
|
66
|
+
*/
|
|
67
|
+
start(): Promise<void>;
|
|
68
|
+
stop(): void;
|
|
69
|
+
/**
|
|
70
|
+
* Remove this instance's row on a clean shutdown, so a coordinator that
|
|
71
|
+
* stopped on purpose is dead to its siblings immediately rather than after
|
|
72
|
+
* the grace window. Best-effort: a crash leaves the row to expire.
|
|
73
|
+
*/
|
|
74
|
+
retire(): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* One heartbeat write. Best-effort: a failed tick is retried on the next.
|
|
77
|
+
*
|
|
78
|
+
* `processStart` is set for the write `start()` makes, and is the only one
|
|
79
|
+
* that rewrites `started_at` — the column records when THIS process came up,
|
|
80
|
+
* so a restart under the same instance id must move it while an ordinary tick
|
|
81
|
+
* must not.
|
|
82
|
+
*/
|
|
83
|
+
beat(opts?: {
|
|
84
|
+
processStart?: boolean;
|
|
85
|
+
}): Promise<void>;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Which of the given coordinator instance ids are alive right now.
|
|
89
|
+
*
|
|
90
|
+
* Reads `cluster_instances` directly rather than the peer registry, for the
|
|
91
|
+
* reason the class above documents: the peer registry is empty during boot and
|
|
92
|
+
* blind under a partition, and a wrong "dead" verdict here means acting on a
|
|
93
|
+
* row a working coordinator owns.
|
|
94
|
+
*/
|
|
95
|
+
export declare function liveInstanceIds(db: Kysely<Database>, instanceIds: readonly string[], graceMs: number): Promise<Set<string>>;
|
|
96
|
+
//# sourceMappingURL=instance-heartbeat.d.ts.map
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* 2. Send join.request with the join token
|
|
7
7
|
* 3. Receive join.response with encrypted config bundle
|
|
8
8
|
* 4. Decrypt bundle using token-derived AES-256-GCM key
|
|
9
|
-
* 5. Write decrypted config as
|
|
9
|
+
* 5. Write the decrypted config as an env file the orchestrator boots from
|
|
10
10
|
*
|
|
11
11
|
* The token carries routing info (cleartext for Platform relay) and a secret
|
|
12
12
|
* (used for HKDF key derivation). Only the joiner and the token creator
|
|
@@ -22,12 +22,23 @@ interface JoinClientOptions {
|
|
|
22
22
|
peerUrl?: string;
|
|
23
23
|
/** API key for Platform authentication (required for --platform mode) */
|
|
24
24
|
apiKey?: string;
|
|
25
|
-
/**
|
|
25
|
+
/**
|
|
26
|
+
* Path to write the resulting local config YAML.
|
|
27
|
+
*
|
|
28
|
+
* @deprecated The orchestrator boots from its environment, so nothing reads
|
|
29
|
+
* this file. Leave it unset and use {@link JoinClientOptions.envFilePath}.
|
|
30
|
+
*/
|
|
26
31
|
configPath?: string;
|
|
32
|
+
/** Path to write the env file `orchestrator install --env-file` consumes. */
|
|
33
|
+
envFilePath?: string;
|
|
27
34
|
}
|
|
35
|
+
/** Default path the join writes its env file to. */
|
|
36
|
+
export declare const DEFAULT_JOIN_ENV_FILE = "./kici-orchestrator.env";
|
|
28
37
|
/**
|
|
29
|
-
* Local config structure written by the
|
|
30
|
-
*
|
|
38
|
+
* Local config structure written by the deprecated `--config` path.
|
|
39
|
+
*
|
|
40
|
+
* @deprecated `loadLocalConfig()` strips `storage` and `secrets`, and the boot
|
|
41
|
+
* path never reads the file at all.
|
|
31
42
|
*/
|
|
32
43
|
interface JoinLocalConfig {
|
|
33
44
|
database: {
|
|
@@ -45,10 +56,48 @@ export declare function decryptAndParseBundle(encryptedB64: string, encryptionKe
|
|
|
45
56
|
/**
|
|
46
57
|
* Build a JoinLocalConfig from a decrypted ConfigBundle.
|
|
47
58
|
* Maps bundle fields to the structure expected by loadLocalConfig().
|
|
59
|
+
*
|
|
60
|
+
* @deprecated Feeds the deprecated `--config` artifact. Use
|
|
61
|
+
* {@link buildEnvFile}.
|
|
48
62
|
*/
|
|
49
63
|
export declare function buildLocalConfig(bundle: ConfigBundle): JoinLocalConfig;
|
|
64
|
+
/**
|
|
65
|
+
* Startup environment variable each `ConfigBundle.storage` field is delivered
|
|
66
|
+
* through.
|
|
67
|
+
*
|
|
68
|
+
* The `satisfies` clause makes a bundle storage field with no entry here a
|
|
69
|
+
* compile error, so the projection cannot silently drop one — which is the
|
|
70
|
+
* whole defect this artifact exists to avoid. The companion test pins the
|
|
71
|
+
* other half: every field `sharedConfigSchema.storage` accepts, and every
|
|
72
|
+
* variable named here, resolves in the startup env definition.
|
|
73
|
+
*/
|
|
74
|
+
export declare const STORAGE_ENV_VARS: {
|
|
75
|
+
readonly type: 'KICI_STORAGE_TYPE';
|
|
76
|
+
readonly bucket: 'KICI_STORAGE_BUCKET';
|
|
77
|
+
readonly prefix: 'KICI_STORAGE_PREFIX';
|
|
78
|
+
readonly region: 'KICI_STORAGE_REGION';
|
|
79
|
+
readonly endpoint: 'KICI_STORAGE_ENDPOINT';
|
|
80
|
+
readonly externalEndpoint: 'KICI_STORAGE_EXTERNAL_ENDPOINT';
|
|
81
|
+
readonly forcePathStyle: 'KICI_STORAGE_FORCE_PATH_STYLE';
|
|
82
|
+
readonly logBucket: 'KICI_STORAGE_LOG_BUCKET';
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Project a decrypted `ConfigBundle` onto the environment variables the
|
|
86
|
+
* orchestrator boot path reads.
|
|
87
|
+
*
|
|
88
|
+
* A value carrying a newline would silently truncate the file, so it is
|
|
89
|
+
* rejected by name rather than written.
|
|
90
|
+
*/
|
|
91
|
+
export declare function buildEnvFile(bundle: ConfigBundle): string;
|
|
92
|
+
/**
|
|
93
|
+
* Write the env file the orchestrator boots from.
|
|
94
|
+
*/
|
|
95
|
+
export declare function writeEnvFile(path: string, bundle: ConfigBundle): Promise<void>;
|
|
50
96
|
/**
|
|
51
97
|
* Write a local config object to a YAML file.
|
|
98
|
+
*
|
|
99
|
+
* @deprecated The orchestrator boot path is environment-only, so nothing reads
|
|
100
|
+
* this file. Use {@link writeEnvFile}.
|
|
52
101
|
*/
|
|
53
102
|
export declare function writeConfigFile(path: string, config: Record<string, unknown>): Promise<void>;
|
|
54
103
|
export declare class JoinClient {
|
|
@@ -59,7 +108,8 @@ export declare class JoinClient {
|
|
|
59
108
|
* 1. Send join.request with token to Platform relay or direct peer
|
|
60
109
|
* 2. Receive join.response with encrypted config bundle
|
|
61
110
|
* 3. Decrypt bundle using token-derived key
|
|
62
|
-
* 4. Write
|
|
111
|
+
* 4. Write the env file the orchestrator boots from (and, when `--config`
|
|
112
|
+
* names one, the deprecated local YAML)
|
|
63
113
|
*/
|
|
64
114
|
join(): Promise<void>;
|
|
65
115
|
/**
|
|
@@ -60,6 +60,22 @@ export declare class OrphanRecovery {
|
|
|
60
60
|
* Only runs when this node is the Raft leader.
|
|
61
61
|
*/
|
|
62
62
|
scanForOrphans(): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Release concurrency slots still marked `active` for a run that has already
|
|
65
|
+
* finished. Run once per leader transition (`start()`), which covers a boot
|
|
66
|
+
* and a failover.
|
|
67
|
+
*
|
|
68
|
+
* A slot outlives its run whenever the release path did not run — a
|
|
69
|
+
* coordinator crash between "the run finished" and "the slot was released".
|
|
70
|
+
* On a `max: 1` deploy gate a single leaked slot blocks every later deploy
|
|
71
|
+
* forever, and nothing else would ever notice: the DB says the slot is held
|
|
72
|
+
* and the run that held it is gone.
|
|
73
|
+
*
|
|
74
|
+
* `getActiveRuns` reconciles the same way inside its own transaction on every
|
|
75
|
+
* acquire, so this is the sweep for a scope nobody happens to ask about —
|
|
76
|
+
* which is why once per leader transition is enough.
|
|
77
|
+
*/
|
|
78
|
+
releaseLeakedConcurrencySlots(): Promise<void>;
|
|
63
79
|
/**
|
|
64
80
|
* Attempt to recover a single potentially orphaned run.
|
|
65
81
|
*/
|
|
@@ -127,6 +127,16 @@ export declare class PeerRegistry {
|
|
|
127
127
|
* Update peer state from a heartbeat message.
|
|
128
128
|
* Updates agent inventory, draining status, capabilities, term, leaderId,
|
|
129
129
|
* and lastHeartbeatAt timestamp.
|
|
130
|
+
*
|
|
131
|
+
* A heartbeat is an ingress into the label-matching domain, so every label
|
|
132
|
+
* it carries is folded here rather than at each comparison site. A peer
|
|
133
|
+
* running an older build sends the case its operator typed — `Docker` — and
|
|
134
|
+
* every consumer of `PeerInfo` compares against folded job selectors, so a
|
|
135
|
+
* consumer that forgets to fold silently stops counting that peer's agents.
|
|
136
|
+
* Folding on arrival means a consumer cannot forget.
|
|
137
|
+
*
|
|
138
|
+
* Identifiers are deliberately NOT folded: `agentId`, `scalerName`, and the
|
|
139
|
+
* scaler's `name` / `type` are opaque and case-sensitive.
|
|
130
140
|
*/
|
|
131
141
|
updateHeartbeat(instanceId: string, heartbeat: PeerHeartbeat): void;
|
|
132
142
|
/**
|
|
@@ -12,27 +12,15 @@
|
|
|
12
12
|
* get permanently stuck on a phantom holder.
|
|
13
13
|
*/
|
|
14
14
|
import type { AgentRegistry } from '../agent/registry.js';
|
|
15
|
-
import type { ConcurrencyGroupTracker } from './group-tracker.js';
|
|
16
15
|
import type { ConcurrencyQueueManager } from './queue-manager.js';
|
|
17
16
|
import type { ConcurrencyWaiters } from './waiters.js';
|
|
18
17
|
export interface DispatchNextQueuedDeps {
|
|
19
|
-
/**
|
|
20
|
-
tracker: ConcurrencyGroupTracker;
|
|
21
|
-
/** DB-backed queue manager. */
|
|
18
|
+
/** The DB arbiter. */
|
|
22
19
|
queueManager: ConcurrencyQueueManager;
|
|
23
20
|
/** Agent registry for finding the waiter's WS. */
|
|
24
21
|
registry: AgentRegistry;
|
|
25
22
|
/** In-memory waiter map. */
|
|
26
23
|
waiters: ConcurrencyWaiters;
|
|
27
|
-
/**
|
|
28
|
-
* Default max for `acquireSlot` when re-syncing the in-memory tracker after
|
|
29
|
-
* a dequeue. The runtime concurrency config (per-workflow `max`) is not
|
|
30
|
-
* available at slot-release time; the dequeued waiter has already been
|
|
31
|
-
* accounted for under that policy when it was originally enqueued, so any
|
|
32
|
-
* value `>= 1` is safe here. We pass 1 because the v1 contract documents
|
|
33
|
-
* single-slot semantics (max>1 is out of scope).
|
|
34
|
-
*/
|
|
35
|
-
trackerMaxFallback?: number;
|
|
36
24
|
}
|
|
37
25
|
/**
|
|
38
26
|
* Try to dequeue the next queued entry for `(group, routingKey)` and notify
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export { ConcurrencyQueueManager, type QueuedJob, type EnqueueOptions } from './queue-manager.js';
|
|
1
|
+
export { ConcurrencyQueueManager, ConcurrencySlotStatus, type QueuedJob, type EnqueueOptions, } from './queue-manager.js';
|
|
3
2
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The arbiter of `concurrency: { group, max }`.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* the
|
|
6
|
-
*
|
|
4
|
+
* Every decision is a transaction against `concurrency_groups`, which is what
|
|
5
|
+
* makes `max` mean the same thing across a restart and across every coordinator
|
|
6
|
+
* in a cluster. A process-local map cannot: a restart came back with an empty
|
|
7
|
+
* map and let a second run deploy alongside the one already deploying, and two
|
|
8
|
+
* coordinators each held their own map so `max: 1` was never cluster-wide.
|
|
9
|
+
* `concurrency: { group, max: 1 }` is the guard customers use to serialise
|
|
10
|
+
* deploys and migrations, so "usually right" is not a useful guarantee.
|
|
7
11
|
*/
|
|
8
|
-
import type
|
|
12
|
+
import { type Kysely } from 'kysely';
|
|
9
13
|
import type { Database } from '../db/types.js';
|
|
14
|
+
/** `concurrency_groups.status` values. */
|
|
15
|
+
export declare enum ConcurrencySlotStatus {
|
|
16
|
+
Active = "active",
|
|
17
|
+
Queued = "queued",
|
|
18
|
+
Completed = "completed",
|
|
19
|
+
Cancelled = "cancelled"
|
|
20
|
+
}
|
|
10
21
|
/** A queued job returned from dequeue operations. */
|
|
11
22
|
export interface QueuedJob {
|
|
12
23
|
id: string;
|
|
@@ -25,20 +36,63 @@ export interface EnqueueOptions {
|
|
|
25
36
|
export declare class ConcurrencyQueueManager {
|
|
26
37
|
private readonly db;
|
|
27
38
|
constructor(db: Kysely<Database>);
|
|
39
|
+
/**
|
|
40
|
+
* Serialise every arbitration for one (routingKey, groupKey) scope.
|
|
41
|
+
*
|
|
42
|
+
* A transaction-scoped advisory lock, so it is released on commit or
|
|
43
|
+
* rollback with no cleanup path to get wrong. Counting active rows and
|
|
44
|
+
* inserting one are two statements, and without the lock two coordinators
|
|
45
|
+
* both read `count < max` and both insert — which is exactly the
|
|
46
|
+
* double-deploy the cap exists to prevent.
|
|
47
|
+
*/
|
|
48
|
+
private static lockScope;
|
|
49
|
+
/**
|
|
50
|
+
* Try to take a slot in a concurrency group.
|
|
51
|
+
*
|
|
52
|
+
* Idempotent: a run that already holds an active slot re-acquires it without
|
|
53
|
+
* consuming a second one, which the partial unique index on
|
|
54
|
+
* `(routing_key, group_key, run_id) WHERE status = 'active'` also enforces at
|
|
55
|
+
* the DB level.
|
|
56
|
+
*
|
|
57
|
+
* @returns whether this run holds a slot afterwards.
|
|
58
|
+
*/
|
|
59
|
+
acquireSlot(groupKey: string, routingKey: string, runId: string, jobId: string, opts: {
|
|
60
|
+
max: number;
|
|
61
|
+
}): Promise<boolean>;
|
|
62
|
+
/** Release this run's slot in a group. No-op when it holds none. */
|
|
63
|
+
releaseSlot(groupKey: string, routingKey: string, runId: string): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* The runs holding an active slot, oldest first.
|
|
66
|
+
*
|
|
67
|
+
* A run whose `execution_runs` row is already terminal is excluded and its
|
|
68
|
+
* slot is released in the same transaction. A slot outlives its run whenever
|
|
69
|
+
* the release path did not run — a coordinator crash between "the run
|
|
70
|
+
* finished" and "the slot was released" — and a leaked slot on a `max: 1`
|
|
71
|
+
* deploy gate blocks every later deploy forever.
|
|
72
|
+
*/
|
|
73
|
+
getActiveRuns(groupKey: string, routingKey: string): Promise<string[]>;
|
|
74
|
+
/** The oldest active run, which `cancelInProgress` supersedes. */
|
|
75
|
+
getOldestRun(groupKey: string, routingKey: string): Promise<string | null>;
|
|
76
|
+
/**
|
|
77
|
+
* Active run ids for a scope, reconciled against `execution_runs`. Must be
|
|
78
|
+
* called with the scope lock already held.
|
|
79
|
+
*/
|
|
80
|
+
private static activeRunIds;
|
|
28
81
|
/**
|
|
29
82
|
* Enqueue a job that is waiting for a concurrency slot.
|
|
30
83
|
* Inserts a row with status='queued' into concurrency_groups.
|
|
31
84
|
*/
|
|
32
85
|
enqueue(opts: EnqueueOptions): Promise<void>;
|
|
33
|
-
/**
|
|
34
|
-
* Record an active slot in the DB for persistence across restarts.
|
|
35
|
-
*/
|
|
36
|
-
recordActive(opts: EnqueueOptions): Promise<void>;
|
|
37
86
|
/**
|
|
38
87
|
* Dequeue the oldest queued job for a concurrency group.
|
|
39
88
|
* Returns null if no queued jobs exist.
|
|
40
89
|
*/
|
|
41
90
|
dequeueNext(groupKey: string, routingKey: string): Promise<QueuedJob | null>;
|
|
91
|
+
/**
|
|
92
|
+
* Promote the oldest queued waiter to `active`. Must be called with the scope
|
|
93
|
+
* lock already held.
|
|
94
|
+
*/
|
|
95
|
+
private static promoteOldestQueued;
|
|
42
96
|
/**
|
|
43
97
|
* Cancel all queued entries for a run.
|
|
44
98
|
* Marks them as 'cancelled' with a completion timestamp.
|
|
@@ -55,14 +109,5 @@ export declare class ConcurrencyQueueManager {
|
|
|
55
109
|
* queued job should be dispatched.
|
|
56
110
|
*/
|
|
57
111
|
onJobComplete(groupKey: string, routingKey: string, runId: string): Promise<QueuedJob | null>;
|
|
58
|
-
/**
|
|
59
|
-
* Load all active entries from DB for hydrating the in-memory tracker.
|
|
60
|
-
* Called on orchestrator startup.
|
|
61
|
-
*/
|
|
62
|
-
loadActiveEntries(): Promise<Array<{
|
|
63
|
-
groupKey: string;
|
|
64
|
-
routingKey: string;
|
|
65
|
-
runId: string;
|
|
66
|
-
}>>;
|
|
67
112
|
}
|
|
68
113
|
//# sourceMappingURL=queue-manager.d.ts.map
|
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
* Convert a KICI_ env var key to a config path array.
|
|
13
13
|
* Returns null for non-KICI_ keys or unknown mappings.
|
|
14
14
|
*
|
|
15
|
-
* Handles
|
|
15
|
+
* Handles three patterns:
|
|
16
16
|
* 1. Direct mappings (KICI_DATABASE_URL -> ['database', 'url'])
|
|
17
|
-
* 2.
|
|
17
|
+
* 2. Startup names whose overlay spelling differs (KICI_PORT -> ['server', 'port'])
|
|
18
|
+
* 3. Multi-app GitHub provider (KICI_PROVIDERS_GITHUB_<NAME>_<FIELD> ->
|
|
18
19
|
* ['providers', 'github', '<name-lowered>', '<camelField>'])
|
|
19
20
|
*/
|
|
20
21
|
export declare function envKeyToConfigPath(key: string): string[] | null;
|
package/dist/config.d.ts
CHANGED
|
@@ -34,6 +34,7 @@ declare const configSchema: z.ZodObject<{
|
|
|
34
34
|
platform: "platform";
|
|
35
35
|
}>>;
|
|
36
36
|
port: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
37
|
+
host: z.ZodDefault<z.ZodString>;
|
|
37
38
|
basePath: z.ZodDefault<z.ZodString>;
|
|
38
39
|
tlsCertPath: z.ZodOptional<z.ZodString>;
|
|
39
40
|
platformUrl: z.ZodOptional<z.ZodString>;
|
|
@@ -42,6 +43,7 @@ declare const configSchema: z.ZodObject<{
|
|
|
42
43
|
provenanceIssuer: z.ZodOptional<z.ZodString>;
|
|
43
44
|
provenanceSigningIssuer: z.ZodOptional<z.ZodString>;
|
|
44
45
|
provenanceSignerKind: z.ZodOptional<z.ZodString>;
|
|
46
|
+
oidcLegacyPrSub: z.ZodPipe<z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>, z.ZodTransform<boolean, string | boolean>>;
|
|
45
47
|
provenanceKmsKeyArn: z.ZodOptional<z.ZodString>;
|
|
46
48
|
provenanceKmsRegion: z.ZodOptional<z.ZodString>;
|
|
47
49
|
provenanceKmsAccessKeyId: z.ZodOptional<z.ZodString>;
|
|
@@ -89,6 +91,7 @@ declare const configSchema: z.ZodObject<{
|
|
|
89
91
|
ingestOverflowReplayIntervalMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
90
92
|
ingestOverflowReplayBatch: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
91
93
|
ingestOverflowMaxAttempts: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
94
|
+
ingestOverflowMaxAgeMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
92
95
|
ingestOverflowClaimTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
93
96
|
rerouteSpawnWindowMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
94
97
|
rerouteAckTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
@@ -129,6 +132,10 @@ declare const configSchema: z.ZodObject<{
|
|
|
129
132
|
dispatchQueueTtlDays: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
130
133
|
stepLogTtlDays: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
131
134
|
checkRunTrackingTtlDays: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
135
|
+
runRetentionDays: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
136
|
+
auditRetentionDays: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
137
|
+
provenanceRetentionDays: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
138
|
+
heldRunRetentionDays: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
132
139
|
reconnectReplayWindowHours: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
133
140
|
cacheBuildTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
134
141
|
cacheMaxTarballBytes: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
@@ -203,6 +210,7 @@ declare const configSchema: z.ZodObject<{
|
|
|
203
210
|
}>>;
|
|
204
211
|
autoMigrate: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<boolean, string>>;
|
|
205
212
|
agentMaxReconnectDelayMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
213
|
+
clusterInstanceHeartbeatMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
206
214
|
otelExporterOtlpEndpoint: z.ZodOptional<z.ZodString>;
|
|
207
215
|
clusterName: z.ZodOptional<z.ZodString>;
|
|
208
216
|
cluster: z.ZodPrefault<z.ZodObject<{
|
|
@@ -237,6 +245,7 @@ export declare const packagingConfigSchema: z.ZodObject<{
|
|
|
237
245
|
platform: "platform";
|
|
238
246
|
}>>;
|
|
239
247
|
port: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
248
|
+
host: z.ZodDefault<z.ZodString>;
|
|
240
249
|
basePath: z.ZodDefault<z.ZodString>;
|
|
241
250
|
tlsCertPath: z.ZodOptional<z.ZodString>;
|
|
242
251
|
platformUrl: z.ZodOptional<z.ZodString>;
|
|
@@ -245,6 +254,7 @@ export declare const packagingConfigSchema: z.ZodObject<{
|
|
|
245
254
|
provenanceIssuer: z.ZodOptional<z.ZodString>;
|
|
246
255
|
provenanceSigningIssuer: z.ZodOptional<z.ZodString>;
|
|
247
256
|
provenanceSignerKind: z.ZodOptional<z.ZodString>;
|
|
257
|
+
oidcLegacyPrSub: z.ZodPipe<z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>, z.ZodTransform<boolean, string | boolean>>;
|
|
248
258
|
provenanceKmsKeyArn: z.ZodOptional<z.ZodString>;
|
|
249
259
|
provenanceKmsRegion: z.ZodOptional<z.ZodString>;
|
|
250
260
|
provenanceKmsAccessKeyId: z.ZodOptional<z.ZodString>;
|
|
@@ -292,6 +302,7 @@ export declare const packagingConfigSchema: z.ZodObject<{
|
|
|
292
302
|
ingestOverflowReplayIntervalMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
293
303
|
ingestOverflowReplayBatch: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
294
304
|
ingestOverflowMaxAttempts: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
305
|
+
ingestOverflowMaxAgeMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
295
306
|
ingestOverflowClaimTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
296
307
|
rerouteSpawnWindowMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
297
308
|
rerouteAckTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
@@ -332,6 +343,10 @@ export declare const packagingConfigSchema: z.ZodObject<{
|
|
|
332
343
|
dispatchQueueTtlDays: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
333
344
|
stepLogTtlDays: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
334
345
|
checkRunTrackingTtlDays: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
346
|
+
runRetentionDays: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
347
|
+
auditRetentionDays: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
348
|
+
provenanceRetentionDays: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
349
|
+
heldRunRetentionDays: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
335
350
|
reconnectReplayWindowHours: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
336
351
|
cacheBuildTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
337
352
|
cacheMaxTarballBytes: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
@@ -406,6 +421,7 @@ export declare const packagingConfigSchema: z.ZodObject<{
|
|
|
406
421
|
}>>;
|
|
407
422
|
autoMigrate: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<boolean, string>>;
|
|
408
423
|
agentMaxReconnectDelayMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
424
|
+
clusterInstanceHeartbeatMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
409
425
|
otelExporterOtlpEndpoint: z.ZodOptional<z.ZodString>;
|
|
410
426
|
clusterName: z.ZodOptional<z.ZodString>;
|
|
411
427
|
cluster: z.ZodPrefault<z.ZodObject<{
|
|
@@ -473,6 +489,7 @@ export type AppConfig = z.infer<typeof configSchema> & {
|
|
|
473
489
|
export declare const envDef: import("@kici-dev/shared/env").DefineEnvResult<{
|
|
474
490
|
mode: "hybrid" | "independent" | "observed" | "platform";
|
|
475
491
|
port: number;
|
|
492
|
+
host: string;
|
|
476
493
|
basePath: string;
|
|
477
494
|
tlsCertPath?: string | undefined;
|
|
478
495
|
platformUrl?: string | undefined;
|
|
@@ -481,6 +498,7 @@ export declare const envDef: import("@kici-dev/shared/env").DefineEnvResult<{
|
|
|
481
498
|
provenanceIssuer?: string | undefined;
|
|
482
499
|
provenanceSigningIssuer?: string | undefined;
|
|
483
500
|
provenanceSignerKind?: string | undefined;
|
|
501
|
+
oidcLegacyPrSub: boolean;
|
|
484
502
|
provenanceKmsKeyArn?: string | undefined;
|
|
485
503
|
provenanceKmsRegion?: string | undefined;
|
|
486
504
|
provenanceKmsAccessKeyId?: string | undefined;
|
|
@@ -525,6 +543,7 @@ export declare const envDef: import("@kici-dev/shared/env").DefineEnvResult<{
|
|
|
525
543
|
ingestOverflowReplayIntervalMs: number;
|
|
526
544
|
ingestOverflowReplayBatch: number;
|
|
527
545
|
ingestOverflowMaxAttempts: number;
|
|
546
|
+
ingestOverflowMaxAgeMs: number;
|
|
528
547
|
ingestOverflowClaimTimeoutMs: number;
|
|
529
548
|
rerouteSpawnWindowMs: number;
|
|
530
549
|
rerouteAckTimeoutMs: number;
|
|
@@ -559,6 +578,10 @@ export declare const envDef: import("@kici-dev/shared/env").DefineEnvResult<{
|
|
|
559
578
|
dispatchQueueTtlDays: number;
|
|
560
579
|
stepLogTtlDays: number;
|
|
561
580
|
checkRunTrackingTtlDays: number;
|
|
581
|
+
runRetentionDays: number;
|
|
582
|
+
auditRetentionDays: number;
|
|
583
|
+
provenanceRetentionDays: number;
|
|
584
|
+
heldRunRetentionDays: number;
|
|
562
585
|
reconnectReplayWindowHours: number;
|
|
563
586
|
cacheBuildTimeoutMs: number;
|
|
564
587
|
cacheMaxTarballBytes: number;
|
|
@@ -612,6 +635,7 @@ export declare const envDef: import("@kici-dev/shared/env").DefineEnvResult<{
|
|
|
612
635
|
nodeEnv: "development" | "production" | "test";
|
|
613
636
|
autoMigrate: boolean;
|
|
614
637
|
agentMaxReconnectDelayMs: number;
|
|
638
|
+
clusterInstanceHeartbeatMs: number;
|
|
615
639
|
otelExporterOtlpEndpoint?: string | undefined;
|
|
616
640
|
clusterName?: string | undefined;
|
|
617
641
|
cluster: {
|
|
@@ -12,6 +12,13 @@ export interface ReleaseQueuedHoldsArgs {
|
|
|
12
12
|
/** Resume a released hold by re-dispatching its job. */
|
|
13
13
|
onJobRelease: (signal: ReleaseSignal) => Promise<void>;
|
|
14
14
|
}
|
|
15
|
+
/** Jobs of one run the caller already accounts for itself. */
|
|
16
|
+
export interface OccupyingJobExclusion {
|
|
17
|
+
/** The run the excluded names belong to. */
|
|
18
|
+
runId: string;
|
|
19
|
+
/** `execution_jobs.job_name` values to leave out of the count. */
|
|
20
|
+
jobNames: readonly string[];
|
|
21
|
+
}
|
|
15
22
|
/**
|
|
16
23
|
* Count the jobs OCCUPYING a slot in a concurrency group, scoped to one org.
|
|
17
24
|
*
|
|
@@ -23,10 +30,25 @@ export interface ReleaseQueuedHoldsArgs {
|
|
|
23
30
|
* one: the release path re-checks the limit precisely so the bound holds
|
|
24
31
|
* whenever the sweep happens to run, and an undercount defeats that re-check.
|
|
25
32
|
*
|
|
33
|
+
* A PLACEHOLDER row is excluded, and that exclusion is what keeps the count
|
|
34
|
+
* from deadlocking the queue it gates. A job the dispatch pass held back — on a
|
|
35
|
+
* `needs` edge, a rolling-wave slot, an invoke-gate summon, or a protection-rule
|
|
36
|
+
* hold — is registered under a `needs-pending-` id at status `pending` so the
|
|
37
|
+
* run stays open for it. It has reached no agent, so it occupies nothing; and
|
|
38
|
+
* counting it meant a queued hold counted against the very limit that gates its
|
|
39
|
+
* own release. One held job in a limit-1 group then read as `free = 1 - 1 = 0`
|
|
40
|
+
* and was never released at all, and the hold sat until the expiry sweep failed
|
|
41
|
+
* it. Its real row, with the dispatcher's own job id, replaces the placeholder
|
|
42
|
+
* the moment it dispatches — so the slot is counted from exactly then.
|
|
43
|
+
*
|
|
26
44
|
* The `customer_id` predicate is not optional: a context name shared across
|
|
27
45
|
* tenants would otherwise leak concurrency between them.
|
|
46
|
+
*
|
|
47
|
+
* `exclude` lets a caller that carries its own in-memory reservation for some
|
|
48
|
+
* of these jobs keep the two terms disjoint. The dispatch gate is the one such
|
|
49
|
+
* caller; the release sweep passes nothing and counts everything.
|
|
28
50
|
*/
|
|
29
|
-
export declare function countOccupyingJobs(db: Kysely<Database>, orgId: string, concurrencyGroup: string): Promise<number>;
|
|
51
|
+
export declare function countOccupyingJobs(db: Kysely<Database>, orgId: string, concurrencyGroup: string, exclude?: OccupyingJobExclusion): Promise<number>;
|
|
30
52
|
/**
|
|
31
53
|
* Release up to `limit - running` queued holds for a group, oldest first.
|
|
32
54
|
* Returns how many actually resumed.
|
|
@@ -21,6 +21,7 @@ export declare function baseAttestationsQuery(db: Kysely<Database>): import("kys
|
|
|
21
21
|
batch_accumulation_items: import("../db/types.js").BatchAccumulationItemsTable;
|
|
22
22
|
batch_accumulation_windows: import("../db/types.js").BatchAccumulationWindowsTable;
|
|
23
23
|
check_run_tracking: import("../db/types.js").CheckRunTrackingTable;
|
|
24
|
+
cluster_instances: import("../db/types.js").ClusterInstancesTable;
|
|
24
25
|
cluster_meta: import("../db/types.js").ClusterMetaTable;
|
|
25
26
|
cluster_settings: import("../db/types.js").ClusterSettingsTable;
|
|
26
27
|
cold_store_chunk_counts: import("../db/types.js").ColdStoreChunkCountsTable;
|
|
@@ -96,6 +97,7 @@ export declare function basePendingAttestationsQuery(db: Kysely<Database>): impo
|
|
|
96
97
|
batch_accumulation_items: import("../db/types.js").BatchAccumulationItemsTable;
|
|
97
98
|
batch_accumulation_windows: import("../db/types.js").BatchAccumulationWindowsTable;
|
|
98
99
|
check_run_tracking: import("../db/types.js").CheckRunTrackingTable;
|
|
100
|
+
cluster_instances: import("../db/types.js").ClusterInstancesTable;
|
|
99
101
|
cluster_meta: import("../db/types.js").ClusterMetaTable;
|
|
100
102
|
cluster_settings: import("../db/types.js").ClusterSettingsTable;
|
|
101
103
|
cold_store_chunk_counts: import("../db/types.js").ColdStoreChunkCountsTable;
|