@kici-dev/orchestrator 0.13.0 → 0.14.1
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 +17 -0
- package/dist/cancel/peer-job-cancel.d.ts +12 -0
- package/dist/cli/api-client.d.ts +73 -0
- package/dist/cli/commands/cluster-settings.d.ts +31 -1
- package/dist/cli/commands/peer.d.ts +27 -1
- package/dist/cli/commands/scaler.d.ts +40 -4
- package/dist/cli.js +2210 -933
- package/dist/cluster/cluster-settings-reader.d.ts +8 -2
- package/dist/cluster/coordinator.d.ts +34 -8
- package/dist/cluster/peer-client.d.ts +37 -4
- package/dist/cluster/peer-forget.d.ts +138 -0
- package/dist/cluster/peer-handler.d.ts +18 -1
- package/dist/cluster/scaler-orphans-peer.d.ts +40 -0
- package/dist/cluster/settings-propagation.d.ts +85 -0
- package/dist/cluster/worker-cluster-settings.d.ts +29 -0
- package/dist/config.d.ts +9 -0
- package/dist/db/migrations/154_cluster_settings_firecracker_api_socket_wait.d.ts +4 -0
- package/dist/db/migrations/155_org_settings_reroute_spawn_retry.d.ts +17 -0
- package/dist/db/migrations/156_kici_events_match_outcome.d.ts +17 -0
- package/dist/db/types.d.ts +16 -0
- package/dist/events/event-router.d.ts +7 -1
- package/dist/events/event-store.d.ts +20 -3
- package/dist/events/types.d.ts +45 -0
- package/dist/helpers/windows-batch.d.ts +59 -0
- package/dist/index.js +60 -0
- package/dist/metrics/prometheus.d.ts +2 -0
- package/dist/orchestrator-core.d.ts +7 -0
- package/dist/registration/registration-store.d.ts +10 -0
- package/dist/routes/admin-cluster-settings.d.ts +13 -1
- package/dist/routes/admin-event-inspect.d.ts +36 -0
- package/dist/routes/admin-peer-forget.d.ts +43 -0
- package/dist/routes/admin-scaler-orphans.d.ts +64 -0
- package/dist/routes/admin.d.ts +23 -0
- package/dist/scaler/backend-factory.d.ts +6 -1
- package/dist/scaler/bare-metal-backend.d.ts +17 -15
- package/dist/scaler/bare-metal-launch.d.ts +90 -0
- package/dist/scaler/firecracker-backend.d.ts +181 -7
- package/dist/scaler/live-vms.d.ts +57 -0
- package/dist/scaler/manager.d.ts +112 -3
- package/dist/scaler/orphan-requests.d.ts +23 -0
- package/dist/scaler/overlay-template.d.ts +38 -0
- package/dist/scaler/scaler-state-store.d.ts +7 -0
- package/dist/scaler/spawn-errors.d.ts +17 -0
- package/dist/scaler/startup-orphan-sweep.d.ts +15 -0
- package/dist/scaler/types.d.ts +21 -2
- package/dist/scaler/vm-job-bindings.d.ts +17 -0
- package/dist/secrets/rbac.d.ts +7 -1
- package/dist/server.js +5498 -2193
- package/dist/standalone.js +10754 -7451
- package/dist/worker/in-memory-execution-tracker.d.ts +5 -0
- package/dist/worker/in-memory-job-queue.d.ts +21 -1
- package/dist/worker/queued-reroute-release.d.ts +39 -0
- package/dist/worker/reroute-spawn-control.d.ts +58 -0
- package/dist/worker/spawn-retry-budget.d.ts +87 -0
- package/dist/worker-core.d.ts +11 -2
- package/installer-image-digests.json +3 -3
- package/package.json +4 -4
- package/sbom.spdx.json +53 -53
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Kysely } from 'kysely';
|
|
2
|
-
import type { Database } from '../db/types.js';
|
|
2
|
+
import type { Database, ClusterSettings } from '../db/types.js';
|
|
3
3
|
/** Numeric columns on cluster_settings readable via {@link ClusterSettingsReader}. */
|
|
4
|
-
export type ClusterNumberColumn = 'max_github_payload_bytes' | 'event_log_max_payload_bytes' | 'lock_file_max_bytes' | 'webhook_dedup_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' | 'sealed_secrets_retry_backoff_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';
|
|
4
|
+
export type ClusterNumberColumn = 'max_github_payload_bytes' | 'event_log_max_payload_bytes' | 'lock_file_max_bytes' | 'webhook_dedup_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' | 'firecracker_api_socket_wait_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' | 'sealed_secrets_retry_backoff_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';
|
|
5
5
|
/** Text columns on cluster_settings readable via {@link ClusterSettingsReader}. */
|
|
6
6
|
export type ClusterStringColumn = 'dashboard_verified_issuer';
|
|
7
7
|
/** Boolean columns on cluster_settings readable via {@link ClusterSettingsReader}. */
|
|
@@ -88,6 +88,12 @@ export declare class ClusterSettingsReader {
|
|
|
88
88
|
*/
|
|
89
89
|
private loadSnapshot;
|
|
90
90
|
private loadRow;
|
|
91
|
+
/**
|
|
92
|
+
* The whole row from one read (undefined when there is no row or the read
|
|
93
|
+
* failed). For a caller that needs several columns that agree with each
|
|
94
|
+
* other, such as a value and the row version it belongs to.
|
|
95
|
+
*/
|
|
96
|
+
getRow(): Promise<ClusterSettings | undefined>;
|
|
91
97
|
/** Resolve a fleet-wide numeric knob; `fallback` is the config.ts cluster default. */
|
|
92
98
|
getNumber(column: ClusterNumberColumn, fallback: number): Promise<number>;
|
|
93
99
|
/**
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - "Peers report step-by-step progress back to coordinator"
|
|
11
11
|
* - "Cancel mode: graceful -- finish current step, cancel remaining"
|
|
12
12
|
*/
|
|
13
|
-
import type { JobReroute, JobProgress, JobProgressAck, PeerScalerEvent, PeerToPeerMessage, ResourceRequest, LabelMatcher } from '@kici-dev/engine';
|
|
13
|
+
import type { JobReroute, JobProgress, JobProgressAck, PeerScalerEvent, PeerToPeerMessage, RerouteSpawnRetry, ResourceRequest, LabelMatcher } from '@kici-dev/engine';
|
|
14
14
|
import type { PeerRegistry } from './peer-registry.js';
|
|
15
15
|
import type { PeerClient } from './peer-client.js';
|
|
16
16
|
import type { Dispatcher } from '../agent/dispatcher.js';
|
|
@@ -114,6 +114,14 @@ export interface RunCoordinatorDeps {
|
|
|
114
114
|
* {@link DEFAULT_MAX_HOPS}.
|
|
115
115
|
*/
|
|
116
116
|
getRerouteMaxHops?: (job: JobToRoute) => Promise<number>;
|
|
117
|
+
/**
|
|
118
|
+
* Per-job spawn-retry budget sent to the receiving peer on `job.reroute` and
|
|
119
|
+
* enforced here on the peer's relayed spawn failures. Resolves the job's org
|
|
120
|
+
* overrides from `org_settings.reroute_spawn_max_attempts` /
|
|
121
|
+
* `reroute_spawn_retry_backoff_ms`, else the cluster defaults. When absent,
|
|
122
|
+
* {@link DEFAULT_REROUTE_SPAWN_RETRY} is used.
|
|
123
|
+
*/
|
|
124
|
+
getRerouteSpawnRetry?: (job: JobToRoute) => Promise<RerouteSpawnRetry>;
|
|
117
125
|
}
|
|
118
126
|
export declare class RunCoordinator {
|
|
119
127
|
private readonly instanceId;
|
|
@@ -128,6 +136,7 @@ export declare class RunCoordinator {
|
|
|
128
136
|
private readonly getRerouteSpawnWindowMs;
|
|
129
137
|
private readonly getRerouteAckTimeoutMs;
|
|
130
138
|
private readonly getRerouteMaxHops;
|
|
139
|
+
private readonly getRerouteSpawnRetry;
|
|
131
140
|
/**
|
|
132
141
|
* Tracks which jobs have been rerouted to which peers, keyed by runId.
|
|
133
142
|
* Used for cancel propagation, progress tracking, and the post-ACK spawn
|
|
@@ -193,12 +202,18 @@ export declare class RunCoordinator {
|
|
|
193
202
|
* line + dispatch-queue last-error column) just as it would for a
|
|
194
203
|
* locally-emitted scaler event.
|
|
195
204
|
*
|
|
196
|
-
* Layer B
|
|
197
|
-
*
|
|
198
|
-
* the reroute
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
205
|
+
* Layer B: a `scaler.failed` for a tracked rerouted job whose spawn window is
|
|
206
|
+
* still armed is the worker reporting that an agent spawn failed after it
|
|
207
|
+
* accepted the reroute. The worker retries within the spawn-retry budget sent on
|
|
208
|
+
* `job.reroute`, and the relay carries its verdict:
|
|
209
|
+
*
|
|
210
|
+
* - `final: true` — the worker gave the job back. Re-dispatch immediately (the
|
|
211
|
+
* same routine the spawn-window timer runs). Idempotent with the Layer A
|
|
212
|
+
* timer: whichever fires first removes the tracking entry.
|
|
213
|
+
* - `final: false` — the worker is retrying. Re-arm the window for one more
|
|
214
|
+
* attempt plus the backoff; treat the `maxAttempts`-th such relay as final.
|
|
215
|
+
* - no verdict — an older worker that retries without a bound. The window
|
|
216
|
+
* armed at the reroute keeps running unchanged.
|
|
202
217
|
*
|
|
203
218
|
* Two guards make the re-dispatch safe. First, source provenance: the failure
|
|
204
219
|
* must come from `fromPeerId === tracked.peerId` (the authenticated connection
|
|
@@ -211,6 +226,16 @@ export declare class RunCoordinator {
|
|
|
211
226
|
* correct regardless of which peer relayed the event.
|
|
212
227
|
*/
|
|
213
228
|
onPeerScalerEvent(msg: PeerScalerEvent, fromPeerId: string): void;
|
|
229
|
+
/**
|
|
230
|
+
* A worker's verdict on a failed spawn for a job it holds. `final: true` means it
|
|
231
|
+
* gave the job back, so re-dispatch now. `final: false` means it is retrying, so
|
|
232
|
+
* restart the window for one more attempt plus the backoff this coordinator told it
|
|
233
|
+
* to wait. No verdict means a worker that retries without a bound, so leave the
|
|
234
|
+
* window as it is. The count caps a worker that never says `final`.
|
|
235
|
+
*/
|
|
236
|
+
private onRelayedSpawnFailure;
|
|
237
|
+
/** Restart a rerouted job's spawn window for one more worker attempt plus its backoff. */
|
|
238
|
+
private rearmAfterSpawnRetry;
|
|
214
239
|
/**
|
|
215
240
|
* Handle peer job completion. Updates ExecutionTracker.
|
|
216
241
|
* The execution tracker's onJobStatus fires the needs-aware scheduler hook,
|
|
@@ -317,7 +342,8 @@ export declare class RunCoordinator {
|
|
|
317
342
|
/**
|
|
318
343
|
* Post-ACK spawn-window backstop. Fires when a rerouted job's peer accepted
|
|
319
344
|
* but produced no progress within the window (Layer A), or immediately when a
|
|
320
|
-
* worker relays
|
|
345
|
+
* worker relays its final spawn-failure verdict for the job (Layer B, via
|
|
346
|
+
* onPeerScalerEvent).
|
|
321
347
|
* Best-effort cancels the original peer (double-execution guard against a
|
|
322
348
|
* slow-but-healthy spawn), then re-runs routing to another peer, then a local
|
|
323
349
|
* fallback, and finally records the job failed rather than leaving it pending.
|
|
@@ -10,8 +10,10 @@
|
|
|
10
10
|
* Authentication uses ECDH key exchange followed by join token (first connect)
|
|
11
11
|
* or HMAC credential proof (reconnection).
|
|
12
12
|
*/
|
|
13
|
-
import { type PeerHeartbeat, type PeerToPeerMessage, type JobReroute, type JobProgress, type JobProgressAck, type PeerJobCancel, type PeerLogChunk, type PeerCacheUploadRequest, type PeerCacheUploadResponse, type PeerConfigReload, type PeerConfigReloadResponse, type PeerClusterSettingsRequest, type PeerClusterSettingsResponse, type PeerLogsCollectRequest, type PeerLeaving, type PeerAgentTokenRevoke, type RaftVoteRequest, type RaftVoteResponse, type RaftAppendEntries } from '@kici-dev/engine';
|
|
13
|
+
import { type PeerHeartbeat, type PeerToPeerMessage, type JobReroute, type JobProgress, type JobProgressAck, type PeerJobCancel, type PeerLogChunk, type PeerCacheUploadRequest, type PeerCacheUploadResponse, type PeerConfigReload, type PeerConfigReloadResponse, type PeerScalerOrphansRequest, type PeerForgetRequest, type PeerForgetResponse, type PeerScalerOrphansResponse, type PeerClusterSettingsRequest, type PeerClusterSettingsResponse, type PeerLogsCollectRequest, type PeerLeaving, type PeerAgentTokenRevoke, type RaftVoteRequest, type RaftVoteResponse, type RaftAppendEntries } from '@kici-dev/engine';
|
|
14
14
|
import type { PeerRegistry } from './peer-registry.js';
|
|
15
|
+
import { type PEER_FORGET_TIMEOUT, type PeerForgetRequestHandler } from './peer-forget.js';
|
|
16
|
+
import { type SCALER_ORPHANS_TIMEOUT, type ScalerOrphansRequestHandler } from './scaler-orphans-peer.js';
|
|
15
17
|
import type { PeerAuthCoordinator } from './peer-auth-coordinator.js';
|
|
16
18
|
/** Logged when this instance has neither a credential file nor a join token. */
|
|
17
19
|
export declare const NO_AUTH_METHOD_MESSAGE = "No peer auth method: this instance has no credential file and no join token";
|
|
@@ -97,6 +99,17 @@ export interface PeerClientOptions {
|
|
|
97
99
|
* If undefined, incoming collect requests are ignored.
|
|
98
100
|
*/
|
|
99
101
|
onLogsCollectRequest?: PeerLogsCollectResponder;
|
|
102
|
+
/**
|
|
103
|
+
* Answers a peer.scaler.orphans.request the connected coordinator forwarded
|
|
104
|
+
* to this node (`kici-admin scaler orphans --target`). If undefined,
|
|
105
|
+
* requests are answered with ok=false.
|
|
106
|
+
*/
|
|
107
|
+
onScalerOrphansRequest?: ScalerOrphansRequestHandler;
|
|
108
|
+
/**
|
|
109
|
+
* Forgets a departed peer the connected coordinator forgot (`kici-admin peer
|
|
110
|
+
* forget`). If undefined, requests are answered with outcome `error`.
|
|
111
|
+
*/
|
|
112
|
+
onPeerForgetRequest?: PeerForgetRequestHandler;
|
|
100
113
|
}
|
|
101
114
|
/**
|
|
102
115
|
* Builds a node's subtree bundle in response to a peer.logs.collect.request and
|
|
@@ -118,6 +131,8 @@ export declare class PeerClient {
|
|
|
118
131
|
private readonly ackWaiters;
|
|
119
132
|
private readonly cacheWaiters;
|
|
120
133
|
private readonly configReloadWaiters;
|
|
134
|
+
private readonly scalerOrphansWaiters;
|
|
135
|
+
private readonly peerForgetWaiters;
|
|
121
136
|
private readonly clusterSettingsWaiters;
|
|
122
137
|
/** Correlates peer.logs.collect.request with the peer's chunked subtree response. */
|
|
123
138
|
private readonly logsCollectWaiters;
|
|
@@ -150,6 +165,8 @@ export declare class PeerClient {
|
|
|
150
165
|
private readonly onPeerConfigReload?;
|
|
151
166
|
private readonly onAuthenticated?;
|
|
152
167
|
private readonly onLogsCollectRequest?;
|
|
168
|
+
private readonly onScalerOrphansRequest?;
|
|
169
|
+
private readonly onPeerForgetRequest?;
|
|
153
170
|
constructor(options: PeerClientOptions);
|
|
154
171
|
/** Current connection state. */
|
|
155
172
|
get state(): PeerConnectionState;
|
|
@@ -189,10 +206,26 @@ export declare class PeerClient {
|
|
|
189
206
|
*/
|
|
190
207
|
sendConfigReloadAndWait(msg: PeerConfigReload, timeoutMs?: number): Promise<PeerConfigReloadResponse | null>;
|
|
191
208
|
/**
|
|
192
|
-
* Send a peer.
|
|
193
|
-
*
|
|
209
|
+
* Send a peer.forget.request to the connected peer and wait for the matching
|
|
210
|
+
* response.
|
|
211
|
+
*
|
|
212
|
+
* @returns the response; null when not connected; `'timeout'` when no
|
|
213
|
+
* response arrived within `timeoutMs`.
|
|
214
|
+
*/
|
|
215
|
+
sendPeerForgetAndWait(msg: PeerForgetRequest, timeoutMs: number): Promise<PeerForgetResponse | null | typeof PEER_FORGET_TIMEOUT>;
|
|
216
|
+
/**
|
|
217
|
+
* Send a peer.scaler.orphans.request to the connected peer and wait for the
|
|
218
|
+
* matching response.
|
|
219
|
+
*
|
|
220
|
+
* @returns the response; null when not connected; `'timeout'` when no
|
|
221
|
+
* response arrived within `timeoutMs`.
|
|
222
|
+
*/
|
|
223
|
+
sendScalerOrphansAndWait(msg: PeerScalerOrphansRequest, timeoutMs: number): Promise<PeerScalerOrphansResponse | null | typeof SCALER_ORPHANS_TIMEOUT>;
|
|
224
|
+
/**
|
|
225
|
+
* Send a peer.clusterSettings.request to the connected coordinator and wait for
|
|
226
|
+
* the matching peer.clusterSettings.response carrying the worker-settings snapshot.
|
|
194
227
|
*
|
|
195
|
-
* @returns The response, or null if not connected or the
|
|
228
|
+
* @returns The response, or null if not connected or the coordinator doesn't reply
|
|
196
229
|
* within the timeout — the caller keeps its current (config-default) settings.
|
|
197
230
|
*/
|
|
198
231
|
sendClusterSettingsRequestAndWait(msg: PeerClusterSettingsRequest, timeoutMs?: number): Promise<PeerClusterSettingsResponse | null>;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { PeerForgetOutcome, type PeerForgetRequest, type PeerForgetResponse } from '@kici-dev/engine';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import type { PeerRegistry } from './peer-registry.js';
|
|
4
|
+
/** What forgetting did on one coordinator. */
|
|
5
|
+
export interface PeerForgetResult {
|
|
6
|
+
/** The coordinator that answered. */
|
|
7
|
+
coordinator: string;
|
|
8
|
+
outcome: PeerForgetOutcome;
|
|
9
|
+
detail: string;
|
|
10
|
+
}
|
|
11
|
+
/** Local outcomes that stop a forget before it reaches any sibling. */
|
|
12
|
+
export declare const LOCAL_REFUSALS: ReadonlySet<PeerForgetOutcome>;
|
|
13
|
+
/** A sibling's answer that never arrived, or a sibling no connection reached. */
|
|
14
|
+
export declare const PEER_FORGET_TIMEOUT = "timeout";
|
|
15
|
+
/** The answer to a forget request a peer that is not a coordinator sent. */
|
|
16
|
+
export declare const PEER_FORGET_COORDINATORS_ONLY = "peer forget requests are accepted from coordinators only";
|
|
17
|
+
/** The answer of a peer with no forget handler wired. */
|
|
18
|
+
export declare const PEER_FORGET_UNHANDLED = "peer forget requests are not handled by this peer";
|
|
19
|
+
/** Which window a coordinator keeps treating a silent peer as alive for. */
|
|
20
|
+
export declare const PeerLivenessWindowKind: z.ZodEnum<{
|
|
21
|
+
"adopter-grace": "adopter-grace";
|
|
22
|
+
"reroute-grace": "reroute-grace";
|
|
23
|
+
"stale-window": "stale-window";
|
|
24
|
+
}>;
|
|
25
|
+
export type PeerLivenessWindowKind = z.infer<typeof PeerLivenessWindowKind>;
|
|
26
|
+
/** How long after its last heartbeat a coordinator still treats a peer as alive. */
|
|
27
|
+
export interface PeerLivenessWindow {
|
|
28
|
+
kind: PeerLivenessWindowKind;
|
|
29
|
+
windowMs: number;
|
|
30
|
+
}
|
|
31
|
+
/** What a coordinator reads to choose a peer's liveness window. */
|
|
32
|
+
export interface PeerLivenessSource {
|
|
33
|
+
/** The peer stale window (`KICI_CLUSTER_PEER_STALE_TIMEOUT_MS`). */
|
|
34
|
+
staleTimeoutMs: number;
|
|
35
|
+
/** Reads the live `reroute_flap_grace_ms` setting. */
|
|
36
|
+
rerouteFlapGraceMs: () => Promise<number>;
|
|
37
|
+
/**
|
|
38
|
+
* This coordinator's event-provision backstop, or null when it runs none.
|
|
39
|
+
* `holdsAdoptedProvisions` reads whether a peer adopted provisions the
|
|
40
|
+
* backstop judges by that peer's liveness.
|
|
41
|
+
*/
|
|
42
|
+
backstop: {
|
|
43
|
+
holdsAdoptedProvisions: (instanceId: string) => Promise<boolean>;
|
|
44
|
+
} | null;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The longest window in which this coordinator still treats `instanceId` as
|
|
48
|
+
* alive after its last heartbeat. Forgetting the peer inside it would cut that
|
|
49
|
+
* grace short: every reader of the registry treats a peer it no longer knows
|
|
50
|
+
* as gone at once.
|
|
51
|
+
*
|
|
52
|
+
* - A peer that adopted provisions gets the event-provision backstop's own
|
|
53
|
+
* grace (`reaperFlapGraceMs`), or the backstop tears its instances down.
|
|
54
|
+
* - Any other peer gets the longer of the stale window and the reroute flap
|
|
55
|
+
* grace, which the rerouted-job guard and the master-key requeue give every
|
|
56
|
+
* disconnected peer whether or not this coordinator runs a backstop.
|
|
57
|
+
*/
|
|
58
|
+
export declare function peerLivenessWindow(instanceId: string, source: PeerLivenessSource): Promise<PeerLivenessWindow>;
|
|
59
|
+
/** The checks a coordinator runs before it forgets a peer. */
|
|
60
|
+
export interface PeerForgetGuards {
|
|
61
|
+
/**
|
|
62
|
+
* How long after its last heartbeat the peer is still treated as alive. A
|
|
63
|
+
* peer heard from inside it may be partitioned rather than gone, so it is kept.
|
|
64
|
+
*/
|
|
65
|
+
liveness: PeerLivenessWindow;
|
|
66
|
+
/**
|
|
67
|
+
* This coordinator's event-provision backstop, or null when it runs none.
|
|
68
|
+
* `configuredPeerCount` is the `KICI_CLUSTER_PEERS` count the backstop's
|
|
69
|
+
* cluster-view check reads beside the live registry.
|
|
70
|
+
*/
|
|
71
|
+
backstop: {
|
|
72
|
+
configuredPeerCount: number;
|
|
73
|
+
} | null;
|
|
74
|
+
/** The operator acknowledged that the forget may switch the backstop back on. */
|
|
75
|
+
acknowledgeBackstop: boolean;
|
|
76
|
+
/** The current time; tests pin it. */
|
|
77
|
+
nowMs?: number;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The guards for forgetting `instanceId` on one coordinator, built from its
|
|
81
|
+
* cluster config, the live reroute flap grace and its event-provision
|
|
82
|
+
* backstop. The backstop runs on every coordinator that runs a scaler manager.
|
|
83
|
+
*/
|
|
84
|
+
export declare function peerForgetGuards(instanceId: string, cluster: {
|
|
85
|
+
peerStaleTimeoutMs: number;
|
|
86
|
+
peers: readonly unknown[];
|
|
87
|
+
}, liveness: Omit<PeerLivenessSource, 'staleTimeoutMs'>, acknowledgeBackstop: boolean): Promise<PeerForgetGuards>;
|
|
88
|
+
/** What forgetting a peer that would switch the backstop back on does. */
|
|
89
|
+
export declare function backstopConsequence(instanceId: string): string;
|
|
90
|
+
/**
|
|
91
|
+
* Drop `instanceId` from `registry` when it names a peer that left the
|
|
92
|
+
* cluster. Kept, with the reason: a connected peer (its next heartbeat would
|
|
93
|
+
* register it again), a peer heard from inside its liveness window (it may be
|
|
94
|
+
* partitioned rather than gone; see `peerLivenessWindow`), and a peer whose removal would switch the
|
|
95
|
+
* event-provision backstop back on, unless the request acknowledged that.
|
|
96
|
+
*/
|
|
97
|
+
export declare function forgetDepartedPeer(registry: PeerRegistry, selfInstanceId: string, instanceId: string, guards: PeerForgetGuards): Omit<PeerForgetResult, 'coordinator'>;
|
|
98
|
+
/** Answers a forget request a sibling coordinator fanned out. */
|
|
99
|
+
export type PeerForgetRequestHandler = (msg: PeerForgetRequest) => Promise<{
|
|
100
|
+
outcome: PeerForgetOutcome;
|
|
101
|
+
detail: string;
|
|
102
|
+
}>;
|
|
103
|
+
/**
|
|
104
|
+
* Answer one forget request with `handler`. A coordinator with no handler
|
|
105
|
+
* answers {@link PEER_FORGET_UNHANDLED}, and a handler that fails (its guards
|
|
106
|
+
* read the database) answers `error`, so the peer is kept and the operator
|
|
107
|
+
* sees why.
|
|
108
|
+
*/
|
|
109
|
+
export declare function replyToPeerForgetRequest(msg: PeerForgetRequest, handler: PeerForgetRequestHandler | undefined, send: (response: PeerForgetResponse) => void, logFields?: Record<string, unknown>): void;
|
|
110
|
+
/**
|
|
111
|
+
* Sends one forget request to a sibling coordinator and waits for its answer.
|
|
112
|
+
* Resolves null when no connection reached the sibling, and
|
|
113
|
+
* {@link PEER_FORGET_TIMEOUT} when it did not answer within `timeoutMs`.
|
|
114
|
+
*/
|
|
115
|
+
export type SendPeerForget = (siblingInstanceId: string, msg: PeerForgetRequest, timeoutMs: number) => Promise<PeerForgetResponse | null | typeof PEER_FORGET_TIMEOUT>;
|
|
116
|
+
/**
|
|
117
|
+
* Forget `instanceId` on this coordinator, then on every connected sibling
|
|
118
|
+
* coordinator, each of which holds its own registry. A peer this coordinator
|
|
119
|
+
* still has connected is refused and not fanned out. The first result is this
|
|
120
|
+
* coordinator's.
|
|
121
|
+
*/
|
|
122
|
+
export declare function forgetAcrossCoordinators(registry: PeerRegistry, selfInstanceId: string, instanceId: string, timeoutMs: number, guards: PeerForgetGuards, send: SendPeerForget): Promise<PeerForgetResult[]>;
|
|
123
|
+
/**
|
|
124
|
+
* The coordinator peers the cluster expects but this coordinator has no live
|
|
125
|
+
* link to: registered coordinators whose connection is down.
|
|
126
|
+
*/
|
|
127
|
+
export declare function disconnectedCoordinatorIds(registry: PeerRegistry, selfInstanceId: string): string[];
|
|
128
|
+
/** Pending forget requests sent to siblings, keyed by message id. */
|
|
129
|
+
export declare class PeerForgetWaiters {
|
|
130
|
+
private readonly waiters;
|
|
131
|
+
/** Wait for the response to `messageId`, or {@link PEER_FORGET_TIMEOUT}. */
|
|
132
|
+
wait(messageId: string, timeoutMs: number): Promise<PeerForgetResponse | typeof PEER_FORGET_TIMEOUT>;
|
|
133
|
+
/** Hand a response to the request waiting for it. An unknown id is dropped. */
|
|
134
|
+
resolve(response: PeerForgetResponse): void;
|
|
135
|
+
/** End every pending wait with an `error` response naming `reason`. */
|
|
136
|
+
rejectAll(reason: string): void;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=peer-forget.d.ts.map
|
|
@@ -6,8 +6,10 @@
|
|
|
6
6
|
* proof (reconnection), registers the peer in PeerRegistry, and routes
|
|
7
7
|
* messages bidirectionally. Sends periodic heartbeats to the connecting peer.
|
|
8
8
|
*/
|
|
9
|
-
import { type PeerHeartbeat, type PeerToPeerMessage, type JobReroute, type JobProgress, type JobProgressAck, type PeerScalerEvent, type PeerJobCancel, type PeerLogChunk, type PeerCacheUploadRequest, type PeerCacheUploadResponse, type PeerConfigReload, type PeerConfigReloadResponse, type PeerClusterSettingsRequest, type WorkerClusterSettings, type PeerLogsCollectRequest, type PeerLeaving, type PeerAgentTokenRevoke, type RaftVoteRequest, type RaftVoteResponse, type RaftAppendEntries } from '@kici-dev/engine';
|
|
9
|
+
import { type PeerHeartbeat, type PeerToPeerMessage, type JobReroute, type JobProgress, type JobProgressAck, type PeerScalerEvent, type PeerJobCancel, type PeerLogChunk, type PeerCacheUploadRequest, type PeerCacheUploadResponse, type PeerConfigReload, type PeerConfigReloadResponse, type PeerScalerOrphansRequest, type PeerForgetRequest, type PeerForgetResponse, type PeerScalerOrphansResponse, type PeerClusterSettingsRequest, type WorkerClusterSettings, type PeerLogsCollectRequest, type PeerLeaving, type PeerAgentTokenRevoke, type RaftVoteRequest, type RaftVoteResponse, type RaftAppendEntries } from '@kici-dev/engine';
|
|
10
10
|
import type { PeerRegistry } from './peer-registry.js';
|
|
11
|
+
import { type PEER_FORGET_TIMEOUT, type PeerForgetRequestHandler } from './peer-forget.js';
|
|
12
|
+
import { type SCALER_ORPHANS_TIMEOUT, type ScalerOrphansRequestHandler } from './scaler-orphans-peer.js';
|
|
11
13
|
import type { PeerCredentialStore } from './peer-credentials.js';
|
|
12
14
|
import { type JoinTokenManager } from './join-token.js';
|
|
13
15
|
/**
|
|
@@ -104,6 +106,19 @@ export interface PeerHandlerDeps {
|
|
|
104
106
|
* If undefined, incoming collect requests are ignored.
|
|
105
107
|
*/
|
|
106
108
|
onLogsCollectRequest?: (msg: PeerLogsCollectRequest, send: (out: PeerToPeerMessage) => boolean) => Promise<void>;
|
|
109
|
+
/**
|
|
110
|
+
* Answers a peer.scaler.orphans.request a coordinator forwarded to this node
|
|
111
|
+
* (`kici-admin scaler orphans --target`). A request from a peer that is not
|
|
112
|
+
* a coordinator is refused before it reaches the handler. If undefined,
|
|
113
|
+
* requests are answered with ok=false.
|
|
114
|
+
*/
|
|
115
|
+
onScalerOrphansRequest?: ScalerOrphansRequestHandler;
|
|
116
|
+
/**
|
|
117
|
+
* Forgets a departed peer a sibling coordinator forgot (`kici-admin peer
|
|
118
|
+
* forget`). A request from a peer that is not a coordinator is refused. If
|
|
119
|
+
* undefined, requests are answered with outcome `error`.
|
|
120
|
+
*/
|
|
121
|
+
onPeerForgetRequest?: PeerForgetRequestHandler;
|
|
107
122
|
}
|
|
108
123
|
/**
|
|
109
124
|
* Create a handler function for incoming peer WebSocket connections.
|
|
@@ -127,6 +142,8 @@ export declare function createPeerHandler(deps: PeerHandlerDeps): {
|
|
|
127
142
|
closePeer: (targetInstanceId: string, code: number, reason: string) => void;
|
|
128
143
|
sendAndWaitAck: (targetInstanceId: string, msg: JobReroute, timeoutMs?: number) => Promise<boolean>;
|
|
129
144
|
sendConfigReloadAndWait: (targetInstanceId: string, msg: PeerConfigReload, timeoutMs?: number) => Promise<PeerConfigReloadResponse | null>;
|
|
145
|
+
sendScalerOrphansAndWait: (targetInstanceId: string, msg: PeerScalerOrphansRequest, timeoutMs: number) => Promise<PeerScalerOrphansResponse | null | typeof SCALER_ORPHANS_TIMEOUT>;
|
|
146
|
+
sendPeerForgetAndWait: (targetInstanceId: string, msg: PeerForgetRequest, timeoutMs: number) => Promise<PeerForgetResponse | null | typeof PEER_FORGET_TIMEOUT>;
|
|
130
147
|
sendLogsCollectAndWait: (targetInstanceId: string, msg: PeerLogsCollectRequest, timeoutMs: number) => Promise<Buffer>;
|
|
131
148
|
getConnectionCount: () => number;
|
|
132
149
|
broadcastHeartbeat: (inventory: Omit<PeerHeartbeat, 'type'>) => void;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The peer-channel half of `kici-admin scaler orphans --target`: answering a
|
|
3
|
+
* forwarded peer.scaler.orphans.request, and correlating the response with
|
|
4
|
+
* the request that is waiting for it. Shared by the outgoing `PeerClient` and
|
|
5
|
+
* the incoming peer handler, which carry the same message pair.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import type { PeerScalerOrphansRequest, PeerScalerOrphansResponse } from '@kici-dev/engine';
|
|
9
|
+
import type { ScalerOrphansAnswer } from '../scaler/orphan-requests.js';
|
|
10
|
+
/** Answers a forwarded request from this node's own host and tracking. */
|
|
11
|
+
export type ScalerOrphansRequestHandler = (msg: PeerScalerOrphansRequest) => Promise<ScalerOrphansAnswer>;
|
|
12
|
+
/** The answer of a peer that has no handler wired. */
|
|
13
|
+
export declare const SCALER_ORPHANS_UNHANDLED_ERROR = "scaler orphan requests are not handled by this peer";
|
|
14
|
+
/** The answer to a request a worker sent: a worker never stops another node's VMs. */
|
|
15
|
+
export declare const SCALER_ORPHANS_COORDINATORS_ONLY_ERROR = "scaler orphan requests are accepted from coordinators only";
|
|
16
|
+
/** A forward that reached no peer, or a peer that did not answer in time. */
|
|
17
|
+
export declare const ScalerOrphansForwardFailure: z.ZodEnum<{
|
|
18
|
+
"not-connected": "not-connected";
|
|
19
|
+
timeout: "timeout";
|
|
20
|
+
}>;
|
|
21
|
+
export type ScalerOrphansForwardFailure = z.infer<typeof ScalerOrphansForwardFailure>;
|
|
22
|
+
/** A wait that ended without a response. */
|
|
23
|
+
export declare const SCALER_ORPHANS_TIMEOUT: "timeout";
|
|
24
|
+
/**
|
|
25
|
+
* Answer one forwarded request through `send`. A missing handler and a
|
|
26
|
+
* handler failure are both answered `ok: false`, so the requester never waits
|
|
27
|
+
* out its timeout for a peer that cannot answer.
|
|
28
|
+
*/
|
|
29
|
+
export declare function replyToScalerOrphansRequest(msg: PeerScalerOrphansRequest, handler: ScalerOrphansRequestHandler | undefined, send: (response: PeerScalerOrphansResponse) => void, logFields?: Record<string, unknown>): void;
|
|
30
|
+
/** Pending scaler orphan requests, keyed by message id. */
|
|
31
|
+
export declare class ScalerOrphansWaiters {
|
|
32
|
+
private readonly waiters;
|
|
33
|
+
/** Wait for the response to `messageId`, or {@link SCALER_ORPHANS_TIMEOUT}. */
|
|
34
|
+
wait(messageId: string, timeoutMs: number): Promise<PeerScalerOrphansResponse | typeof SCALER_ORPHANS_TIMEOUT>;
|
|
35
|
+
/** Hand a response to the request waiting for it. An unknown id is dropped. */
|
|
36
|
+
resolve(response: PeerScalerOrphansResponse): void;
|
|
37
|
+
/** End every pending wait with an `ok: false` response naming `reason`. */
|
|
38
|
+
rejectAll(reason: string): void;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=scaler-orphans-peer.d.ts.map
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which cluster-settings version each orchestrator in a cluster has applied,
|
|
3
|
+
* compared with the version of the shared `cluster_settings` row.
|
|
4
|
+
*
|
|
5
|
+
* A worker reports the version of the snapshot it pulled, which is the one its
|
|
6
|
+
* next spawn reads. A coordinator reports the version its settings reader
|
|
7
|
+
* currently serves. Pure, because `kici-admin cluster-settings show` imports
|
|
8
|
+
* it to validate and render the report the admin route builds.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import type { PeerInfo } from './peer-registry.js';
|
|
12
|
+
export declare const settingsPropagationStatusSchema: z.ZodEnum<{
|
|
13
|
+
ahead: "ahead";
|
|
14
|
+
behind: "behind";
|
|
15
|
+
"in-sync": "in-sync";
|
|
16
|
+
}>;
|
|
17
|
+
export type SettingsPropagationStatus = z.infer<typeof settingsPropagationStatusSchema>;
|
|
18
|
+
export declare const SettingsPropagationStatus: {
|
|
19
|
+
ahead: "ahead";
|
|
20
|
+
behind: "behind";
|
|
21
|
+
"in-sync": "in-sync";
|
|
22
|
+
};
|
|
23
|
+
export declare const settingsPropagationRoleSchema: z.ZodEnum<{
|
|
24
|
+
coordinator: "coordinator";
|
|
25
|
+
worker: "worker";
|
|
26
|
+
}>;
|
|
27
|
+
export declare const settingsPropagationEntrySchema: z.ZodObject<{
|
|
28
|
+
instanceId: z.ZodString;
|
|
29
|
+
role: z.ZodEnum<{
|
|
30
|
+
coordinator: "coordinator";
|
|
31
|
+
worker: "worker";
|
|
32
|
+
}>;
|
|
33
|
+
self: z.ZodBoolean;
|
|
34
|
+
connected: z.ZodBoolean;
|
|
35
|
+
appliedVersion: z.ZodNumber;
|
|
36
|
+
status: z.ZodEnum<{
|
|
37
|
+
ahead: "ahead";
|
|
38
|
+
behind: "behind";
|
|
39
|
+
"in-sync": "in-sync";
|
|
40
|
+
}>;
|
|
41
|
+
lastHeartbeatAt: z.ZodNullable<z.ZodString>;
|
|
42
|
+
lastHeartbeatAgeMs: z.ZodNullable<z.ZodNumber>;
|
|
43
|
+
}, z.core.$loose>;
|
|
44
|
+
export type SettingsPropagationEntry = z.infer<typeof settingsPropagationEntrySchema>;
|
|
45
|
+
export declare const settingsPropagationReportSchema: z.ZodObject<{
|
|
46
|
+
currentVersion: z.ZodNumber;
|
|
47
|
+
reportedBy: z.ZodString;
|
|
48
|
+
generatedAt: z.ZodString;
|
|
49
|
+
orchestrators: z.ZodArray<z.ZodObject<{
|
|
50
|
+
instanceId: z.ZodString;
|
|
51
|
+
role: z.ZodEnum<{
|
|
52
|
+
coordinator: "coordinator";
|
|
53
|
+
worker: "worker";
|
|
54
|
+
}>;
|
|
55
|
+
self: z.ZodBoolean;
|
|
56
|
+
connected: z.ZodBoolean;
|
|
57
|
+
appliedVersion: z.ZodNumber;
|
|
58
|
+
status: z.ZodEnum<{
|
|
59
|
+
ahead: "ahead";
|
|
60
|
+
behind: "behind";
|
|
61
|
+
"in-sync": "in-sync";
|
|
62
|
+
}>;
|
|
63
|
+
lastHeartbeatAt: z.ZodNullable<z.ZodString>;
|
|
64
|
+
lastHeartbeatAgeMs: z.ZodNullable<z.ZodNumber>;
|
|
65
|
+
}, z.core.$loose>>;
|
|
66
|
+
}, z.core.$loose>;
|
|
67
|
+
export type SettingsPropagationReport = z.infer<typeof settingsPropagationReportSchema>;
|
|
68
|
+
/** The peer-registry fields a report reads. */
|
|
69
|
+
export type PropagationPeer = Pick<PeerInfo, 'instanceId' | 'role' | 'connected' | 'lastHeartbeatAt' | 'clusterSettingsVersion'>;
|
|
70
|
+
/**
|
|
71
|
+
* `ahead` means the row's version went backwards. A worker in that state never
|
|
72
|
+
* pulls again, because it pulls only when a coordinator advertises a higher
|
|
73
|
+
* version than its own.
|
|
74
|
+
*/
|
|
75
|
+
export declare function classifySettingsVersion(applied: number, current: number): SettingsPropagationStatus;
|
|
76
|
+
export declare function buildSettingsPropagationReport(input: {
|
|
77
|
+
currentVersion: number;
|
|
78
|
+
self: {
|
|
79
|
+
instanceId: string;
|
|
80
|
+
appliedVersion: number;
|
|
81
|
+
};
|
|
82
|
+
peers: readonly PropagationPeer[];
|
|
83
|
+
now: number;
|
|
84
|
+
}): SettingsPropagationReport;
|
|
85
|
+
//# sourceMappingURL=settings-propagation.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The cluster-settings snapshot a coordinator serves to DB-less workers.
|
|
3
|
+
*
|
|
4
|
+
* A worker cannot read `cluster_settings`, so every knob it applies at spawn
|
|
5
|
+
* reaches it through this snapshot, pulled over the peer channel whenever a
|
|
6
|
+
* coordinator advertises a newer settings version. Each value is the stored
|
|
7
|
+
* override, or the serving coordinator's configured default when the column
|
|
8
|
+
* is NULL.
|
|
9
|
+
*/
|
|
10
|
+
import type { WorkerClusterSettings } from '@kici-dev/engine';
|
|
11
|
+
import type { ClusterSettingsReader } from './cluster-settings-reader.js';
|
|
12
|
+
/** The configured defaults behind each snapshot field. */
|
|
13
|
+
export interface WorkerClusterSettingDefaults {
|
|
14
|
+
agentTokenTtlMs: number;
|
|
15
|
+
firecrackerApiSocketWaitMs: number;
|
|
16
|
+
}
|
|
17
|
+
/** A worker snapshot and the `cluster_settings.version` its values belong to. */
|
|
18
|
+
export interface WorkerClusterSettingsSnapshot {
|
|
19
|
+
version: number;
|
|
20
|
+
settings: WorkerClusterSettings;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the worker snapshot and its version from ONE read of the row. A
|
|
24
|
+
* worker stores the version with the values and pulls again only when a
|
|
25
|
+
* coordinator advertises a higher version, so a version read separately from
|
|
26
|
+
* the values could pair a newer version with older values for good.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveWorkerClusterSettingsSnapshot(reader: Pick<ClusterSettingsReader, 'getRow'>, defaults: WorkerClusterSettingDefaults): Promise<WorkerClusterSettingsSnapshot>;
|
|
29
|
+
//# sourceMappingURL=worker-cluster-settings.d.ts.map
|
package/dist/config.d.ts
CHANGED
|
@@ -72,6 +72,7 @@ declare const configSchema: z.ZodObject<{
|
|
|
72
72
|
globalEvalCandidateTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
73
73
|
globalEvalCacheMax: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
74
74
|
globalEvalWaitTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
75
|
+
firecrackerApiSocketWaitMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
75
76
|
queueMaxDepth: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
76
77
|
queueTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
77
78
|
unroutableGraceMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
@@ -104,6 +105,8 @@ declare const configSchema: z.ZodObject<{
|
|
|
104
105
|
rerouteSpawnWindowMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
105
106
|
rerouteAckTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
106
107
|
rerouteMaxHops: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
108
|
+
rerouteSpawnMaxAttempts: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
109
|
+
rerouteSpawnRetryBackoffMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
107
110
|
rerouteFlapGraceMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
108
111
|
scalerSpawnTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
109
112
|
backupStalenessWarnHours: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
@@ -283,6 +286,7 @@ export declare const packagingConfigSchema: z.ZodObject<{
|
|
|
283
286
|
globalEvalCandidateTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
284
287
|
globalEvalCacheMax: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
285
288
|
globalEvalWaitTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
289
|
+
firecrackerApiSocketWaitMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
286
290
|
queueMaxDepth: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
287
291
|
queueTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
288
292
|
unroutableGraceMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
@@ -315,6 +319,8 @@ export declare const packagingConfigSchema: z.ZodObject<{
|
|
|
315
319
|
rerouteSpawnWindowMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
316
320
|
rerouteAckTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
317
321
|
rerouteMaxHops: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
322
|
+
rerouteSpawnMaxAttempts: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
323
|
+
rerouteSpawnRetryBackoffMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
318
324
|
rerouteFlapGraceMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
319
325
|
scalerSpawnTimeoutMs: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
320
326
|
backupStalenessWarnHours: z.ZodDefault<z.ZodCoercedNumber<unknown>>;
|
|
@@ -527,6 +533,7 @@ export declare const envDef: import("@kici-dev/shared/env").DefineEnvResult<{
|
|
|
527
533
|
globalEvalCandidateTimeoutMs: number;
|
|
528
534
|
globalEvalCacheMax: number;
|
|
529
535
|
globalEvalWaitTimeoutMs: number;
|
|
536
|
+
firecrackerApiSocketWaitMs: number;
|
|
530
537
|
queueMaxDepth: number;
|
|
531
538
|
queueTimeoutMs: number;
|
|
532
539
|
unroutableGraceMs: number;
|
|
@@ -556,6 +563,8 @@ export declare const envDef: import("@kici-dev/shared/env").DefineEnvResult<{
|
|
|
556
563
|
rerouteSpawnWindowMs: number;
|
|
557
564
|
rerouteAckTimeoutMs: number;
|
|
558
565
|
rerouteMaxHops: number;
|
|
566
|
+
rerouteSpawnMaxAttempts: number;
|
|
567
|
+
rerouteSpawnRetryBackoffMs: number;
|
|
559
568
|
rerouteFlapGraceMs: number;
|
|
560
569
|
scalerSpawnTimeoutMs: number;
|
|
561
570
|
backupStalenessWarnHours: number;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Kysely } from 'kysely';
|
|
2
|
+
/**
|
|
3
|
+
* Add the two per-org spawn-retry columns a worker applies to a rerouted job (both nullable):
|
|
4
|
+
*
|
|
5
|
+
* - `reroute_spawn_max_attempts INTEGER` — agent spawns a worker attempts for one rerouted
|
|
6
|
+
* job before it gives the job back to its coordinator. NULL falls back to the cluster
|
|
7
|
+
* default (`rerouteSpawnMaxAttempts`, 3).
|
|
8
|
+
* - `reroute_spawn_retry_backoff_ms BIGINT` — wait after a failed spawn before the next
|
|
9
|
+
* attempt. NULL falls back to `rerouteSpawnRetryBackoffMs` (5 s).
|
|
10
|
+
*
|
|
11
|
+
* Operators tune them per org via `kici-admin org-settings reroute set`.
|
|
12
|
+
*
|
|
13
|
+
* Idempotent: each add is guarded on column existence.
|
|
14
|
+
*/
|
|
15
|
+
export declare function up(db: Kysely<unknown>): Promise<void>;
|
|
16
|
+
export declare function down(db: Kysely<unknown>): Promise<void>;
|
|
17
|
+
//# sourceMappingURL=155_org_settings_reroute_spawn_retry.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Kysely } from 'kysely';
|
|
2
|
+
/**
|
|
3
|
+
* Record how the event router resolved each internal event:
|
|
4
|
+
*
|
|
5
|
+
* - `match_outcome TEXT` — `matched`, `buffered`, `no-registration`,
|
|
6
|
+
* `no-target-repo`, `trust-blocked` or `no-trigger-match`.
|
|
7
|
+
* - `matched_count INTEGER` — how many registrations the event was dispatched to.
|
|
8
|
+
*
|
|
9
|
+
* Both are written when the event is processed and are NULL before that, and
|
|
10
|
+
* for rows processed before these columns existed. Nullable with no default,
|
|
11
|
+
* so the ALTER is catalog-only on a large table.
|
|
12
|
+
*
|
|
13
|
+
* Idempotent: `ADD COLUMN IF NOT EXISTS`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function up(db: Kysely<unknown>): Promise<void>;
|
|
16
|
+
export declare function down(db: Kysely<unknown>): Promise<void>;
|
|
17
|
+
//# sourceMappingURL=156_kici_events_match_outcome.d.ts.map
|