@mark1russell7/service 0.5.15 → 0.5.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -17,6 +17,7 @@ This release has the declaration, its export, the law, the health runtime, the l
17
17
  - **The linter.** `lint(description, scenario, rules)` applies the service rules (`SERVICE_RULES`) to a declaration. The declaration binds the symbols of the service: the polls of its checks, the windows of its policies, its drain. The scenario binds the symbols of the platform and of each dependency. A `depends` finding names the symbols that have no bound.
18
18
  - **The claims of a scenario.** A default is true only for a version: the keep-alive of Node is 5 s, but 65 s on main. Thus a value of the scenario can be a claim that names its epoch: `{ epoch: "node@22", value }`. Each finding then gives the epoch of each value that its rule reads (`epochs`).
19
19
  - **A measured value.** A claim can give a distribution by its statistics: `{ epoch, distribution: { p50, p99 } }`. The law binds the p99. A distribution without a p99 binds nothing, thus each rule that reads it depends.
20
+ - **The four ways that a pod stops.** `STOPS` gives the steps of each way. A deletion and a liveness restart have the preStop hook and the drain. A crash and an OOM stop have neither. `lintStop(description, scenario, rules, way)` applies only the rules of the drain that guard that way: O04 for a deletion, O09 for a liveness restart. For a crash or an OOM stop, a finding of `STOP_RULE` depends on the time until the kubelet finds the exit.
20
21
  - **The scopes of a rule.** A rule about a client applies one time for each dependency. A rule about a consumer, for example O20, applies one time for each consumer and each worker.
21
22
  - **The loops of a progress check.** A check of the step `progress` can name the loops that mark it, with its stall time: `marks: { loops, stall }`. Each loop is a check or a worker of the service.
22
23
  - **The stall time.** `lint()` compares the stall time with the longest gap between two marks of the slowest loop (`PROGRESS_RULE`). A loop marks at the end of each turn, also a turn that fails. The gap of a check is `interval × (1 + jitter) + timeout`. The gap of a worker is its sleep or its longest backoff, the longer one, plus `unit_processing_time`. At 300 s ± 20 % and a timeout of 10 s, a poll gives 370 s.
package/build/index.d.ts CHANGED
@@ -257,6 +257,52 @@ export declare const compressionOf: (svc: ServiceDescription, scenario: Scenario
257
257
  */
258
258
  export declare const lint: (svc: ServiceDescription, scenario: Scenario, rules: readonly Rule[]) => Finding[];
259
259
  //#endregion
260
+ //#region src/stops.d.ts
261
+ /**
262
+ * This module keeps apart the four ways that a pod stops (B11). Each way runs a different part of
263
+ * the shutdown, thus a different set of the rules of the drain guards it.
264
+ */
265
+ /** A way that a pod stops: a deletion, a liveness restart, a crash, or a stop for lack of memory (OOM). */
266
+ type StopWay = "deletion" | "liveness-restart" | "crash" | "oom";
267
+ /** What a way of stopping runs, and the rules of the drain that guard it. */
268
+ interface Stop {
269
+ readonly way: StopWay;
270
+ /** This is the signal that the process gets first, or null when the process exits by itself. */
271
+ readonly signal: "SIGTERM" | "SIGKILL" | null;
272
+ /** This flag tells if the kubelet runs the preStop hook. */
273
+ readonly preStop: boolean;
274
+ /** This flag tells if the process runs its shutdown phases. */
275
+ readonly drain: boolean;
276
+ /**
277
+ * This is how the pod leaves its endpoints: by its deletion, when its readiness fails, or when
278
+ * the kubelet finds that the container exited.
279
+ */
280
+ readonly leaves: "deletion" | "readiness" | "exit";
281
+ /** These are the identifiers of the rules of the drain that guard this way. */
282
+ readonly rules: readonly string[];
283
+ }
284
+ /** These are the rules of the drain. Each way of stopping applies only its own rules of this set. */
285
+ export declare const DRAIN_RULE_IDS: readonly string[];
286
+ /**
287
+ * These are the four ways that a pod stops.
288
+ * - A deletion runs the preStop hook, then SIGTERM. The endpoints drop the pod at its deletion,
289
+ * thus the preStop sleep and the hold must cover the propagation (O04).
290
+ * - A liveness restart also runs the preStop hook and SIGTERM, with the grace. The pod stays in its
291
+ * endpoints until its readiness fails, thus readiness must fail first (O09).
292
+ * - A crash and an OOM stop run no hook and no drain. The kubelet finds the exit at its relist, and
293
+ * no rule bounds that time. A client that can reissue a request is the only guard.
294
+ */
295
+ export declare const STOPS: Readonly<Record<StopWay, Stop>>;
296
+ /** The identifier of the finding of a way of stopping that runs no drain. */
297
+ export declare const STOP_RULE = "stop";
298
+ /**
299
+ * This function applies the rules to a declaration for one way of stopping. A rule of the drain
300
+ * applies only when it guards that way. The other rules apply as `lint()` applies them. A way with
301
+ * no drain also gets a finding of `STOP_RULE` that depends. No rule bounds the time until the
302
+ * kubelet finds the exit, and the work in flight is lost.
303
+ */
304
+ export declare const lintStop: (svc: ServiceDescription, scenario: Scenario, rules: readonly Rule[], way: StopWay) => Finding[];
305
+ //#endregion
260
306
  //#region src/worker.d.ts
261
307
  /**
262
308
  * These are the knobs of a worker loop, by the names of the ordering law where the law has them.
@@ -386,5 +432,5 @@ export declare const drainMachine: (description: ServiceDescription) => Machine;
386
432
  /** These are the static machines of the runtime, by the name that their events carry. */
387
433
  export declare const MACHINES: Readonly<Record<Exclude<MachineName, "drain" | "client">, Machine>>;
388
434
  //#endregion
389
- export { type Allowed, type Backoff, type Binding, type Bound, type Cancel, type Change, type Check, type CheckFn, type CheckMetrics, type CheckVerdict, type Claim, type Clock, type Compressed, type Compression, type Controller, type ControllerBuilder, type CooperativeFloor, type Coupling, DURATION_FRACTIONS, type Decision, type DelayBand, type Dependency, type DependencyHandle, type DurationHistogram, EPISODES_KEPT, EXIT_SIGNALS, type EmbeddedProcess, type Episode, type Epochs, type Evaluated, type ExitCodes, type ExitSignal, type ExitTrigger, FORMAT, type FailsBy, type Finding, type Gate, type Health, type HealthMetrics, type HealthServer, type HealthVerdict, type Heartbeat, type HeartbeatOptions, type HostStream, type Idempotency, type Inequality, type IterationContext, type Jitter, type JobAction, type JobContext, type JobFailure, type JobSettle, type JobSource, type KeyState, type KeyedLimiter, type Lifecycle, type LifecycleEvent, type LifecycleState, type LimitPolicy, type LimitRule, type Limiter, type LimiterEviction, type LimiterSpec, type LimiterState, type LimiterStore, type LimiterStoreSpec, type MachineName, type MemoryStore, type MessageShape, type MessageTrigger, type Operation, type OperationOf, type Outcome, PROCESS_TRIGGERS, type Phase, type PhaseContext, type PhaseWork, type PlatformClockOptions, type PodTiming, type Poll, type ProbeAnswer, type ProbeKind, type ProcessHost, type ProcessPort, type ProcessTrigger, type Profile, type ProgressMarks, type QueueDrain, type QueueDrainOptions, type QueueKnobs, type Recorder, type RedeliveryPolicy, type RefusalCause, type Refused, type RepeatSignal, type RequestEnd, type RequestEvent, type RequestFn, type RequestOptions, type RequestStream, type RequestWork, type RequeueCause, type Result, type RoutePattern, type RouteRequest, type Rule, type RunOptions, SLIDING_WINDOW_MACHINE, STAGES, type Scenario, type ScenarioValue, type ScopedChange, type ServiceBuilder, type ServiceDescription, type ShutdownOptions, type Side, type SlidingWindow, type Span, type Stage, type StartOptions, type Statistic, type Step, type StoreFailure, TOKEN_BUCKET_MACHINE, type TakeRequest, type TakeStep, type Term, type TimerMark, type TimerMarks, type Timing, type TokenBucket, type Transport, type TransportImpl, type UnitRequest, type Verdict, type Watchdog, type WatchdogSpec, type WorkerKnobs, type WorkerLoop, type WorkerLoopOptions, asDebounce, asWindow, backoffBand, backoffDelay, backoffProblems, cooperativeAbortAt, daemon, decide, detectionTime, embeddedProcess, ephemeral, failSpan, freeAt, heartbeat, heartbeatDetection, idleSpan, isExitCode, isExitSignal, isMessageShape, keyedLimiter, kubernetes, limitRule, limiterMachine, limiterProblems, limiterStateOf, localDev, longestRetryAfter, matchesMessage, mayReissue, memoryStore, nodeProcess, platformClock, processPortOf, queueDrain, realClock, recoverSpan, redact, redeliverOnce, replay, retryAfterSeconds, service, stageRank, watchdog };
435
+ export { type Allowed, type Backoff, type Binding, type Bound, type Cancel, type Change, type Check, type CheckFn, type CheckMetrics, type CheckVerdict, type Claim, type Clock, type Compressed, type Compression, type Controller, type ControllerBuilder, type CooperativeFloor, type Coupling, DURATION_FRACTIONS, type Decision, type DelayBand, type Dependency, type DependencyHandle, type DurationHistogram, EPISODES_KEPT, EXIT_SIGNALS, type EmbeddedProcess, type Episode, type Epochs, type Evaluated, type ExitCodes, type ExitSignal, type ExitTrigger, FORMAT, type FailsBy, type Finding, type Gate, type Health, type HealthMetrics, type HealthServer, type HealthVerdict, type Heartbeat, type HeartbeatOptions, type HostStream, type Idempotency, type Inequality, type IterationContext, type Jitter, type JobAction, type JobContext, type JobFailure, type JobSettle, type JobSource, type KeyState, type KeyedLimiter, type Lifecycle, type LifecycleEvent, type LifecycleState, type LimitPolicy, type LimitRule, type Limiter, type LimiterEviction, type LimiterSpec, type LimiterState, type LimiterStore, type LimiterStoreSpec, type MachineName, type MemoryStore, type MessageShape, type MessageTrigger, type Operation, type OperationOf, type Outcome, PROCESS_TRIGGERS, type Phase, type PhaseContext, type PhaseWork, type PlatformClockOptions, type PodTiming, type Poll, type ProbeAnswer, type ProbeKind, type ProcessHost, type ProcessPort, type ProcessTrigger, type Profile, type ProgressMarks, type QueueDrain, type QueueDrainOptions, type QueueKnobs, type Recorder, type RedeliveryPolicy, type RefusalCause, type Refused, type RepeatSignal, type RequestEnd, type RequestEvent, type RequestFn, type RequestOptions, type RequestStream, type RequestWork, type RequeueCause, type Result, type RoutePattern, type RouteRequest, type Rule, type RunOptions, SLIDING_WINDOW_MACHINE, STAGES, type Scenario, type ScenarioValue, type ScopedChange, type ServiceBuilder, type ServiceDescription, type ShutdownOptions, type Side, type SlidingWindow, type Span, type Stage, type StartOptions, type Statistic, type Step, type Stop, type StopWay, type StoreFailure, TOKEN_BUCKET_MACHINE, type TakeRequest, type TakeStep, type Term, type TimerMark, type TimerMarks, type Timing, type TokenBucket, type Transport, type TransportImpl, type UnitRequest, type Verdict, type Watchdog, type WatchdogSpec, type WorkerKnobs, type WorkerLoop, type WorkerLoopOptions, asDebounce, asWindow, backoffBand, backoffDelay, backoffProblems, cooperativeAbortAt, daemon, decide, detectionTime, embeddedProcess, ephemeral, failSpan, freeAt, heartbeat, heartbeatDetection, idleSpan, isExitCode, isExitSignal, isMessageShape, keyedLimiter, kubernetes, limitRule, limiterMachine, limiterProblems, limiterStateOf, localDev, longestRetryAfter, matchesMessage, mayReissue, memoryStore, nodeProcess, platformClock, processPortOf, queueDrain, realClock, recoverSpan, redact, redeliverOnce, replay, retryAfterSeconds, service, stageRank, watchdog };
390
436
  //# sourceMappingURL=index.d.ts.map
package/build/index.js CHANGED
@@ -2858,6 +2858,89 @@ const lint = (svc, scenario, rules) => {
2858
2858
  return findings;
2859
2859
  };
2860
2860
  //#endregion
2861
+ //#region src/stops.ts
2862
+ /** These are the rules of the drain. Each way of stopping applies only its own rules of this set. */
2863
+ const DRAIN_RULE_IDS = [
2864
+ "O04",
2865
+ "O09",
2866
+ "O10",
2867
+ "O16"
2868
+ ];
2869
+ /**
2870
+ * These are the four ways that a pod stops.
2871
+ * - A deletion runs the preStop hook, then SIGTERM. The endpoints drop the pod at its deletion,
2872
+ * thus the preStop sleep and the hold must cover the propagation (O04).
2873
+ * - A liveness restart also runs the preStop hook and SIGTERM, with the grace. The pod stays in its
2874
+ * endpoints until its readiness fails, thus readiness must fail first (O09).
2875
+ * - A crash and an OOM stop run no hook and no drain. The kubelet finds the exit at its relist, and
2876
+ * no rule bounds that time. A client that can reissue a request is the only guard.
2877
+ */
2878
+ const STOPS = {
2879
+ deletion: {
2880
+ way: "deletion",
2881
+ signal: "SIGTERM",
2882
+ preStop: true,
2883
+ drain: true,
2884
+ leaves: "deletion",
2885
+ rules: [
2886
+ "O04",
2887
+ "O10",
2888
+ "O16"
2889
+ ]
2890
+ },
2891
+ "liveness-restart": {
2892
+ way: "liveness-restart",
2893
+ signal: "SIGTERM",
2894
+ preStop: true,
2895
+ drain: true,
2896
+ leaves: "readiness",
2897
+ rules: [
2898
+ "O09",
2899
+ "O10",
2900
+ "O16"
2901
+ ]
2902
+ },
2903
+ crash: {
2904
+ way: "crash",
2905
+ signal: null,
2906
+ preStop: false,
2907
+ drain: false,
2908
+ leaves: "exit",
2909
+ rules: []
2910
+ },
2911
+ oom: {
2912
+ way: "oom",
2913
+ signal: "SIGKILL",
2914
+ preStop: false,
2915
+ drain: false,
2916
+ leaves: "exit",
2917
+ rules: []
2918
+ }
2919
+ };
2920
+ /** The identifier of the finding of a way of stopping that runs no drain. */
2921
+ const STOP_RULE = "stop";
2922
+ /**
2923
+ * This function applies the rules to a declaration for one way of stopping. A rule of the drain
2924
+ * applies only when it guards that way. The other rules apply as `lint()` applies them. A way with
2925
+ * no drain also gets a finding of `STOP_RULE` that depends. No rule bounds the time until the
2926
+ * kubelet finds the exit, and the work in flight is lost.
2927
+ */
2928
+ const lintStop = (svc, scenario, rules, way) => {
2929
+ const stop = STOPS[way];
2930
+ const applies = rules.filter((rule) => !DRAIN_RULE_IDS.includes(rule.id) || stop.rules.includes(rule.id));
2931
+ const findings = lint(svc, scenario, applies);
2932
+ if (stop.drain) return findings;
2933
+ return [...findings, {
2934
+ rule: STOP_RULE,
2935
+ scope: svc.name,
2936
+ verdict: "depends",
2937
+ statement: `a ${way} runs no preStop hook and no drain, and no rule bounds the time until the kubelet finds the exit`,
2938
+ window: "the work in flight is lost, and the endpoints keep the pod until the kubelet finds the exit",
2939
+ evaluated: [],
2940
+ unbound: ["exit_detection@pod"]
2941
+ }];
2942
+ };
2943
+ //#endregion
2861
2944
  //#region src/profiles.ts
2862
2945
  const s = (value) => ({
2863
2946
  value,
@@ -3844,6 +3927,6 @@ const MACHINES = {
3844
3927
  watchdog: WATCHDOG_MACHINE
3845
3928
  };
3846
3929
  //#endregion
3847
- export { DECLARATION_RULE, DURATION_FRACTIONS, EPISODES_KEPT, EXIT_MACHINE, EXIT_SIGNALS, FORMAT, GATE_MACHINE, LATCH_MACHINE, LAW_STATISTIC, LIMITER_RULES, MACHINES, PLATFORM_MARKS, POLLER_MACHINE, PROCESS_TRIGGERS, PROGRESS_RULE, SERVICE_RULES, SLIDING_WINDOW_MACHINE, STAGES, TOKEN_BUCKET_MACHINE, WATCHDOG_MACHINE, WINDOW_MACHINE, asDebounce, asWindow, backoffBand, backoffDelay, backoffProblems, capKnob, compress, compression, compressionOf, cooperativeAbortAt, daemon, decide, detectionTime, drainMachine, embeddedProcess, ephemeral, evaluate, failSpan, freeAt, heartbeat, heartbeatDetection, idleSpan, inequalities, isExitCode, isExitSignal, isMessageShape, keyedLimiter, kubernetes, limitRule, limiterMachine, limiterProblems, limiterStateOf, lint, localDev, longestRetryAfter, matchesMessage, mayReissue, memoryStore, nodeProcess, platformClock, processPortOf, queueDrain, realClock, recoverSpan, redact, redeliverOnce, replay, retryAfterSeconds, service, serviceBindings, stageRank, symbolsOf, verdictOf, watchdog, workerLoop };
3930
+ export { DECLARATION_RULE, DRAIN_RULE_IDS, DURATION_FRACTIONS, EPISODES_KEPT, EXIT_MACHINE, EXIT_SIGNALS, FORMAT, GATE_MACHINE, LATCH_MACHINE, LAW_STATISTIC, LIMITER_RULES, MACHINES, PLATFORM_MARKS, POLLER_MACHINE, PROCESS_TRIGGERS, PROGRESS_RULE, SERVICE_RULES, SLIDING_WINDOW_MACHINE, STAGES, STOPS, STOP_RULE, TOKEN_BUCKET_MACHINE, WATCHDOG_MACHINE, WINDOW_MACHINE, asDebounce, asWindow, backoffBand, backoffDelay, backoffProblems, capKnob, compress, compression, compressionOf, cooperativeAbortAt, daemon, decide, detectionTime, drainMachine, embeddedProcess, ephemeral, evaluate, failSpan, freeAt, heartbeat, heartbeatDetection, idleSpan, inequalities, isExitCode, isExitSignal, isMessageShape, keyedLimiter, kubernetes, limitRule, limiterMachine, limiterProblems, limiterStateOf, lint, lintStop, localDev, longestRetryAfter, matchesMessage, mayReissue, memoryStore, nodeProcess, platformClock, processPortOf, queueDrain, realClock, recoverSpan, redact, redeliverOnce, replay, retryAfterSeconds, service, serviceBindings, stageRank, symbolsOf, verdictOf, watchdog, workerLoop };
3848
3931
 
3849
3932
  //# sourceMappingURL=index.js.map