@mark1russell7/service 0.5.12 → 0.5.14
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 +95 -1
- package/build/{builder-DawJhq4p.d.ts → builder-CsSO4LzB.d.ts} +2 -2
- package/build/{core-C2wnF4mg.d.ts → core-D8iXeoE4.d.ts} +54 -4
- package/build/dial-DJolDmOK.d.ts +16 -0
- package/build/grpc.d.ts +307 -0
- package/build/grpc.js +859 -0
- package/build/grpc.js.map +1 -0
- package/build/http-client.d.ts +248 -0
- package/build/http-client.js +612 -0
- package/build/http-client.js.map +1 -0
- package/build/http.d.ts +1 -1
- package/build/index.d.ts +5 -149
- package/build/index.js +119 -3
- package/build/index.js.map +1 -1
- package/build/{lifecycle-fgYfxrHK.d.ts → lifecycle-CMedxaQd.d.ts} +60 -2
- package/build/{machine-Czfb6fV4.js → machine-DZMb_QEU.js} +204 -8
- package/build/machine-DZMb_QEU.js.map +1 -0
- package/build/mongodb.d.ts +307 -0
- package/build/mongodb.js +688 -0
- package/build/mongodb.js.map +1 -0
- package/build/pg.d.ts +2 -2
- package/build/pg.js +30 -33
- package/build/pg.js.map +1 -1
- package/build/queue-CndiCVaY.d.ts +150 -0
- package/build/rabbitmq.d.ts +294 -0
- package/build/rabbitmq.js +748 -0
- package/build/rabbitmq.js.map +1 -0
- package/build/redis.d.ts +4 -10
- package/build/redis.js +6 -38
- package/build/redis.js.map +1 -1
- package/build/testing.d.ts +2 -2
- package/build/testing.js +1 -0
- package/build/testing.js.map +1 -1
- package/build/websocket.d.ts +275 -0
- package/build/websocket.js +780 -0
- package/build/websocket.js.map +1 -0
- package/package.json +38 -1
- package/build/machine-Czfb6fV4.js.map +0 -1
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ This release has the declaration, its export, the law, the health runtime, the l
|
|
|
10
10
|
- **No defaults.** The runtime has no defaults of its own. Thus `describe()` refuses a service that does not declare its readiness, its liveness, its startup budget, its shutdown phases or its cooperative window. It also refuses a service that does not declare what a repeat signal does. The error tells which. `start()` also refuses a check without its function.
|
|
11
11
|
- **One timing shape.** Each policy has a `Timing`: a debounce of polls, or a window of time. Each converts to the other (`asWindow`, `asDebounce`). `failSpan` and `recoverSpan` give the earliest and the latest time to detect a change. At 3 polls of 5 s ± 20 %, a latch fails in 8–18 s on an error, and in 12–22 s on a 4 s timeout.
|
|
12
12
|
- **Checks.** A check names the step of the connection that it examines (`dial`, `round-trip`, `checkout` and others). It also tells if it uses the connection of the application, and which policy it controls. The policy has no default.
|
|
13
|
+
- **The catalog of a client.** The checks of each client name the steps that they gate: `steps: { "round-trip": "readiness" }`. With `catalog: true`, the client also gives a check for each other step that it has. These checks gate nothing and poll each 30 s. A nominated step that the client does not have then fails the attach. The name of each check is the pair of the component and the step (`db.round-trip`).
|
|
13
14
|
- **Idempotency for each operation.** One dependency has the two kinds of operation. A Redis GET is safe to send again. An INCR that goes again after a timeout counts two times. Thus each operation of a dependency, and each route of a controller, declares if it can go again: `true`, `false`, or keyed.
|
|
14
15
|
- **Keyed operations.** A keyed operation has the window that the server keeps its key for. `mayReissue` answers from the declaration of an operation. An operation without a declaration does not go again.
|
|
15
16
|
- **The law.** `evaluate` and `verdictOf` decide one rule of the timer-ordering law on one binding. A rule is data: linear inequalities over `symbol@hop`, with a margin. A verdict is `holds`, `violated`, `unbounded` (it holds only because a timer is absent) or `depends` (nothing is bound).
|
|
@@ -29,6 +30,7 @@ The format of a description is `mark1russell7.service/1`.
|
|
|
29
30
|
|
|
30
31
|
- **Checks on their own loops.** Each check polls on a fixed delay from the start of each poll, with its jitter. Each poll has a timeout, and the runtime aborts the signal of the check at that timeout. An answer is `"ok"`, `"error"` or `"indeterminate"`. A throw is an error with a flag. An indeterminate poll measured nothing, thus it moves no streak.
|
|
31
32
|
- **A pending use is not started again.** While a use of a check is pending, each later poll fails at once with the same cause. Thus a check that hangs fails a debounce of two polls or more as fast as an error does (`failSpan(timing, poll, "hang")`).
|
|
33
|
+
- **The metrics.** `health.metrics()` gives the counts of the runtime, and starts no check. For each check, it counts each outcome, each throw and each forced failure. Its histogram counts the durations of the polls. The bounds are fractions of the timeout of the poll, and a poll that timed out goes into `timedOut`. Its last 8 episodes of failure each go from the first error to the next pass. The cause of an episode has no user, password or token (`redact`). It also counts each transition of the machines of the runtime.
|
|
32
34
|
- **A latch for each check that gates a policy.** A debounce counts polls in sequence. A window measures time on the monotonic clock from the first failure of a sequence. A readiness latch starts tripped, thus readiness is earned. A liveness latch starts released.
|
|
33
35
|
- **The start.** `start()` makes one warm-up sweep of each check, bounded by each timeout, and then starts the loops. The startup probe fails until the sweep ends. `svc.health` gives the runtime from the start of `start()`, thus the probes can answer during the sweep. The verdict says when the sweep outlasts the startup budget.
|
|
34
36
|
- **The verdicts.** `health.verdict()` gives started, draining, ready, alive, each controller, each dependency and each check. The service is ready when it started, it does not drain, and each readiness latch is released. A controller is ready when its own dependencies are ready. Thus a failed dependency fails only the controllers that need it.
|
|
@@ -527,13 +529,103 @@ const life = await app.run(); // the process exits after SIGTERM, with 0 or 1
|
|
|
527
529
|
- **The close.** At the shutdown, the client ends the pool, and it destroys each socket that stays at its `close_bound`.
|
|
528
530
|
- **The manifestations and the machine.** `meets` lists the manifestations and their detectors. `PG_CLIENT_MACHINE` is the client as a `mark1russell7.machine/1` document, and the tests replay the client against it.
|
|
529
531
|
|
|
532
|
+
## The MongoDB client
|
|
533
|
+
|
|
534
|
+
`@mark1russell7/service/mongodb` is the MongoDB client of the service, over a `MongoClient` of the driver 7. This entry is a part of S6. mongodb is an optional peer dependency. The client loads it only when it connects.
|
|
535
|
+
|
|
536
|
+
- **The declaration.** `mongoClient(name, spec)` declares `connect_bound`, `request_timeout`, `statement_timeout`, `heartbeat_interval`, `client_retry_window`, `checkout_timeout`, `pool_idle_expiry`, `keepalive_idle`, `max_connection_age`, `close_bound` and `retrans_giveup_time`. The client derives `driver_writeoff_time` from the connect bound and the heartbeat.
|
|
537
|
+
- **The problems of a spec.** `specProblems` refuses a knob that the driver cannot use. Examples are a zero, which the driver reads as no timer, a heartbeat below 500 ms, and a finite connection age.
|
|
538
|
+
- **The starting knobs.** `MONGO_STARTING_KNOBS` and `MONGO_STARTING_POLL` are a declaration from the cells of S1. Each value has its measured reason in its doc comment.
|
|
539
|
+
- **The settings of the driver.** The client turns off the retries of the driver, thus the core decides each second send. The client also writes `maxTimeMS` in each command, because `db.command` does not add it.
|
|
540
|
+
- **Three outcomes.** `command(operation, document)` gives `ok`, `error` or `indeterminate`. A server error is certain, except an interruption and a write concern error. A failed selection or a closed pool did not send the command.
|
|
541
|
+
- **Idempotency for each operation.** A command document does not tell if it changes a state. Thus the client sends again only an idempotent operation that its table names. The second send waits for a writable server in `client_retry_window`.
|
|
542
|
+
- **The join.** At each new connection, the client records the connection id of the server (`joins`). The driver gives no local socket, thus the local end is null.
|
|
543
|
+
- **No unheard error.** The client listens to the error event of the driver. In Node, an error with no listener ends the process.
|
|
544
|
+
- **The checks.** `checks({ poll, steps })` gives `local-state` (the view of the topology), `round-trip` (a `ping` on the connection of the application) and `dial` (a hello on a new connection).
|
|
545
|
+
- **The close.** At the shutdown, the client closes the driver, and it records `close.bound` at its `close_bound`. The driver gives no socket to destroy, thus its close goes on in the background.
|
|
546
|
+
- **The manifestations and the machine.** `meets` lists the manifestations and their detectors. `MONGO_CLIENT_MACHINE` is the client as a `mark1russell7.machine/1` document, and the tests replay the client against it.
|
|
547
|
+
|
|
548
|
+
## The RabbitMQ client
|
|
549
|
+
|
|
550
|
+
`@mark1russell7/service/rabbitmq` is the RabbitMQ client of the service, over amqplib 2. This entry is a part of S6. The peer dependency amqplib is optional. The client loads it only when it connects.
|
|
551
|
+
|
|
552
|
+
- **The declaration.** `rabbitClient(name, spec)` declares `connect_bound`, `request_timeout`, `heartbeat_interval`, `retry_base`, `retry_cap`, `keepalive_idle`, `max_connection_age`, `close_bound` and `retrans_giveup_time`. The client derives `heartbeat_detection_time` (3 heartbeats) and `idle_refresh_interval` (a half heartbeat).
|
|
553
|
+
- **The problems of a spec.** `specProblems` refuses a knob that amqplib cannot use. Examples are a zero, which amqplib reads as no timer, a heartbeat that is not a whole number of seconds, and a finite connection age.
|
|
554
|
+
- **The starting knobs.** `RABBIT_STARTING_KNOBS` and `RABBIT_STARTING_POLL` are a declaration from the cells of R3. Each value has its measured reason in its doc comment.
|
|
555
|
+
- **A call.** A call is a publish on a confirm channel until its confirm, or an RPC until its reply, for example `basic.get`. The client ends each call at `request_timeout`, because amqplib has no timer for them.
|
|
556
|
+
- **Three outcomes.** `publish(operation, message)` and `get(operation, queue)` give `ok`, `error` or `indeterminate`. An ack is `ok`. A reply code of the broker is certain. A nack, a timeout and the end of the channel before the confirm are not certain. A call while the client is not ready, or while a resource alarm blocks it, did not leave the client.
|
|
557
|
+
- **Idempotency for each operation.** A message does not tell if its consumers remove duplicates. Thus the client sends again only an idempotent operation that its table names. The second send waits for a ready client, in the bound of the call.
|
|
558
|
+
- **One generation.** The client has one connection and one confirm channel. The end of either one ends the generation. The client then connects again by itself, to the next node, after a backoff from `retry_base` to `retry_cap`. The built-in recovery of amqplib stays off.
|
|
559
|
+
- **The join.** At each generation, the client records the node and the name of the connection, `local:port -> remote:port` (`joins`).
|
|
560
|
+
- **The jobs of a queue drain.** `jobs(operation, queue)` gives the source and the settle of `queueDrain`. The count of deliveries comes from `x-delivery-count`. A message that arrives after its call ended goes back to its queue at once.
|
|
561
|
+
- **No unheard error.** The client listens to the error events of the connection and of the channel. In Node, an error with no listener ends the process.
|
|
562
|
+
- **The checks.** `checks({ poll, steps })` gives `local-state`, `round-trip` (a passive declare of `amq.direct` on the channel of the application) and `dial` (the protocol header on a new connection, with no login).
|
|
563
|
+
- **The close.** At the shutdown, the client sends `connection.close`, and it destroys the socket at its `close_bound`.
|
|
564
|
+
- **The manifestations and the machine.** `meets` lists the manifestations and their detectors. `RABBIT_CLIENT_MACHINE` is the client as a `mark1russell7.machine/1` document, and the tests replay the client against it.
|
|
565
|
+
|
|
566
|
+
## The HTTP client
|
|
567
|
+
|
|
568
|
+
`@mark1russell7/service/http-client` is the HTTP client of the service, over an `http.Agent` of Node with keep-alive. This entry is a part of S6. The entry `./http` is the server edge of a service, thus the client has its own name. `node:http` is a built-in, thus the entry has no peer dependency. The client loads `node:http` only when it connects.
|
|
569
|
+
|
|
570
|
+
- **The declaration.** `httpClient(name, spec)` declares `connect_bound`, `request_timeout`, `pool_idle_expiry`, `hint_buffer`, `keepalive_idle`, `max_connection_age`, `close_bound` and `retrans_giveup_time`. Keepalive is also the `idle_refresh_interval`, because the agent sends nothing on a free socket.
|
|
571
|
+
- **The idle close of the server.** The knob `server_idle_close` is not in the declaration, because the scenario binds the close of the server. `problems` compares it with `pool_idle_expiry` (O01).
|
|
572
|
+
- **The problems of a spec.** `specProblems` refuses a knob that the agent cannot use. An example is a free socket timer of 0, which the agent reads as no timer. Others are a keepalive that is not a whole number of seconds, and a finite connection age.
|
|
573
|
+
- **The options of the agent.** `agentOptions(spec)` gives `timeout`, `agentKeepAliveTimeoutBuffer`, `keepAliveMsecs`, `maxSockets` and `maxFreeSockets` from the declaration, and `scheduling: "lifo"`.
|
|
574
|
+
- **The starting knobs.** `HTTP_CLIENT_STARTING_KNOBS` and `HTTP_CLIENT_STARTING_POLL` are a declaration from the HTTP cells. Each value has its measured reason in its doc comment.
|
|
575
|
+
- **A call.** A call is one request until the end of the body of its response. The client ends each call at `request_timeout`, and each connect of a new socket at `connect_bound`, because the agent has no timer for them.
|
|
576
|
+
- **Three outcomes.** `request(call)` gives `ok`, `error` or `indeterminate`. Each whole response is `ok`, with its status: RFC 9110 does not say that a 5xx did not apply. A request that did not get a connected socket did not leave the client. A failure after that is not certain.
|
|
577
|
+
- **Idempotency for each method.** The table names each method by RFC 9110. GET, HEAD, OPTIONS, TRACE, PUT and DELETE are idempotent, and POST and PATCH are not. A spec can name a keyed operation, for example a POST with an `Idempotency-Key`.
|
|
578
|
+
- **The keep-alive race.** A server can close a free socket while a request goes on it. The client then sends again only an idempotent operation, one time, on a new socket. It records `reuse.failed`.
|
|
579
|
+
- **The join.** At each new socket, the client records the ends of the socket (`joins`). HTTP gives no id of a connection.
|
|
580
|
+
- **The checks.** `checks({ poll, steps })` gives `local-state`, `round-trip` (the check request through the pool, which fails at a status of 500 or more) and `dial` (`OPTIONS *` on a new connection). The check request is `OPTIONS *`, or the `check` of the spec.
|
|
581
|
+
- **The close.** At the shutdown, the client waits for its calls in flight. At its `close_bound`, it destroys each socket of the agent, and each call that stays is indeterminate.
|
|
582
|
+
- **The manifestations and the machine.** `meets` lists the manifestations and their detectors. `HTTP_CLIENT_MACHINE` is the client as a `mark1russell7.machine/1` document, and the tests replay the client against it.
|
|
583
|
+
|
|
584
|
+
## The WebSocket client
|
|
585
|
+
|
|
586
|
+
`@mark1russell7/service/websocket` is the WebSocket client of the service, over ws 8. This entry is a part of S6. The peer dependency ws is optional. The client loads it only when it connects.
|
|
587
|
+
|
|
588
|
+
- **The declaration.** `wsClient(name, spec)` declares `connect_bound`, `request_timeout`, `heartbeat_interval`, `heartbeat_timeout`, `retry_base`, `retry_cap`, `keepalive_idle`, `max_connection_age`, `close_bound` and `retrans_giveup_time`. The client derives `heartbeat_detection_time` and `idle_refresh_interval` (the heartbeat).
|
|
589
|
+
- **The problems of a spec.** `specProblems` refuses a knob that ws cannot use. Examples are a zero heartbeat, a keepalive that is not a whole number of seconds, and a finite connection age. It also refuses a password: give the credentials in `headers`.
|
|
590
|
+
- **The starting knobs.** `WS_CLIENT_STARTING_KNOBS`, `WS_CLIENT_STARTING_MISSES` and `WS_CLIENT_STARTING_POLL` are a declaration from the WS cells. Each value has its measured reason in its doc comment.
|
|
591
|
+
- **A call.** A call is a request message until its reply, or a ping frame until its pong. WebSocket has no reply of its own, thus `replies` of the spec reads the id of a reply in a message. The client ends each call at `request_timeout`.
|
|
592
|
+
- **Three outcomes.** `request(operation, { id, data })` and `ping()` give `ok`, `error` or `indeterminate`. A reply that carries an error is certain. A failed write, a timeout and the end of the generation are not certain. A call while the client is not ready did not leave the client.
|
|
593
|
+
- **Messages with no reply.** `send(data)` writes a message, and it is not a call. `onMessage(listener)` gets each message that answers no request.
|
|
594
|
+
- **Idempotency for each operation.** A message does not tell its idempotency. Thus the client sends again only an idempotent operation that its table names. `WS_OPERATIONS` names `ping`. The second send waits for a ready client.
|
|
595
|
+
- **The heartbeat.** The client sends a ping frame at each `heartbeat_interval`, one at a time. After `heartbeatMisses` pings with no pong in `heartbeat_timeout`, `terminate()` destroys the socket.
|
|
596
|
+
- **One generation.** The generation is one connection after its upgrade. At its end, the client connects again by itself, after a backoff from `retry_base` to `retry_cap`.
|
|
597
|
+
- **The join.** At each generation, the client records the URL, the subprotocol and the ends of the socket (`joins`). WebSocket gives no id of a connection.
|
|
598
|
+
- **The checks.** `checks({ poll, steps })` gives `local-state`, `round-trip` (a ping on the connection of the application) and `dial` (the upgrade GET on a new connection, which must get 101).
|
|
599
|
+
- **The close.** At the shutdown, the client waits for its calls in flight, then it sends a close frame. At its `close_bound`, `terminate()` destroys the socket, and each call that stays is indeterminate.
|
|
600
|
+
- **The manifestations and the machine.** `meets` lists the manifestations and their detectors. `WS_CLIENT_MACHINE` is the client as a `mark1russell7.machine/1` document, and the tests replay the client against it.
|
|
601
|
+
|
|
602
|
+
## The gRPC client
|
|
603
|
+
|
|
604
|
+
`@mark1russell7/service/grpc` is the gRPC client of the service, over grpc-js 1.14. This entry is a part of S6. The peer dependency `@grpc/grpc-js` is optional. The client loads it only when it connects.
|
|
605
|
+
|
|
606
|
+
- **The declaration.** `grpcClient(name, spec)` declares `connect_bound`, `request_timeout`, `keepalive_time`, `keepalive_timeout`, `client_idle_timeout`, `retry_base`, `retry_cap`, `keepalive_idle`, `max_connection_age`, `close_bound` and `retrans_giveup_time`. The client derives `heartbeat_detection_time` (the PING) and `idle_refresh_interval`.
|
|
607
|
+
- **The facts of the server.** The knobs `server_keepalive_min_time` and `server_idle_close` are not in the declaration. `problems` compares them with `keepalive_time` (O26) and `client_idle_timeout` (O01).
|
|
608
|
+
- **The problems of a spec.** `specProblems` refuses a knob that grpc-js cannot use. Examples are a zero keepalive, a timer that is not a whole number of milliseconds, and an idle timeout below 1 s. A timer above the longest timer of Node is a problem too. It also refuses a TCP keepalive and a password: give the credentials in `metadata`.
|
|
609
|
+
- **The options of the channel.** `grpcOptions(spec)` gives the target and each timer of grpc-js from the declaration. It also turns the retries of grpc-js off, and the service config of the resolver.
|
|
610
|
+
- **The starting knobs.** `GRPC_CLIENT_STARTING_KNOBS`, `GRPC_CLIENT_STARTING_WITHOUT_CALLS` and `GRPC_CLIENT_STARTING_POLL` are a declaration from the gRPC cells. Each value has its measured reason in its doc comment.
|
|
611
|
+
- **A call.** A call is one unary call until its status. `request` and the response are the bytes of the messages, thus the caller encodes them. A stream is not a call. The deadline of a call is the time that is left in `request_timeout`, and grpc-js sends it as `grpc-timeout`.
|
|
612
|
+
- **Three outcomes.** `call(method, request)` gives `ok`, `error` or `indeterminate` from the status code (`grpcOutcome`). A code that tells a refusal is certain. A status that tells that the call did not leave the client is not sent. Each other status is not certain.
|
|
613
|
+
- **Idempotency for each method.** `grpcOperations` makes the table from the `idempotency_level` of each method in its proto. The client sends again only an idempotent method, one time, after it is ready again. `GRPC_OPERATIONS` names the Check of the health service.
|
|
614
|
+
- **One channel.** The client has one channel for its life, and each READY is one generation. The grpc-js driver connects again by itself after its backoff. The client connects an IDLE channel again at once.
|
|
615
|
+
- **The join.** At each generation, the client records the target (`joins`). The grpc-js driver gives no socket, thus the ends of the socket are null.
|
|
616
|
+
- **The checks.** `checks({ poll, steps })` gives `local-state`, `round-trip` (a Check of the health service on the channel of the application, which passes only for SERVING) and `dial` (the HTTP/2 preface on a new connection, which must get a SETTINGS frame).
|
|
617
|
+
- **The close.** At the shutdown, the client waits for its calls in flight. At its `close_bound`, it cancels each call that stays, which is then indeterminate. Then it closes the channel.
|
|
618
|
+
- **The manifestations and the machine.** `meets` lists the manifestations and their detectors. `GRPC_CLIENT_MACHINE` is the client as a `mark1russell7.machine/1` document, and the tests replay the client against it.
|
|
619
|
+
|
|
530
620
|
## Installation
|
|
531
621
|
|
|
532
622
|
```sh
|
|
533
623
|
pnpm add @mark1russell7/service
|
|
534
624
|
```
|
|
535
625
|
|
|
536
|
-
For the Redis client, the application also installs `ioredis@6`. For the PostgreSQL client, it installs `pg@8`.
|
|
626
|
+
For the Redis client, the application also installs `ioredis@6`. For the PostgreSQL client, it installs `pg@8`. For the MongoDB client, it installs `mongodb@7`. For the RabbitMQ client, it installs `amqplib@2`. For the WebSocket client, it installs `ws@8`.
|
|
627
|
+
|
|
628
|
+
For the gRPC client, it installs `@grpc/grpc-js@1`. The HTTP client needs no other package.
|
|
537
629
|
|
|
538
630
|
The package uses [`@mark1russell7/quantity`](https://www.npmjs.com/package/@mark1russell7/quantity) for each amount. No entry of the service loads `zod` at run time, thus `zod` is an optional peer dependency. An application that validates amounts with the schemas of `quantity` installs `zod`.
|
|
539
631
|
|
|
@@ -644,6 +736,8 @@ for await (const event of stream) {
|
|
|
644
736
|
- **The machines.** Each document is valid, consistent and readable by the algebra. Eight scenarios replay against the documents and reach each state. The timers of the documents give the times of the runtime. The ordering law (O16) agrees with the clamp of the cooperative abort.
|
|
645
737
|
- **The contract.** The contract of a sample declaration passes. The contract also finds a blind dependency, a check whose timeout is too short, and a check that names the wrong dependency.
|
|
646
738
|
- **The Redis client.** These tests use a fake ioredis and a fake clock. They cover the declaration, the three outcomes, and the commands that the client sends again or not. They also cover the join, the backoff, the watchdog, the close, the checks and the manifestations. Five scenarios replay against the document of the client.
|
|
739
|
+
- **The HTTP client.** These tests use a fake agent and a fake clock. They cover the declaration, the three outcomes, the methods that the client sends again or not, and the keep-alive race. They also cover the free socket timer, the close, the checks and the manifestations. Five scenarios replay against the document of the client. One test sends requests through the agent of Node to a server of the loopback.
|
|
740
|
+
- **The gRPC client.** These tests use a fake channel and a fake clock. They cover the declaration, the outcome of each status code, the methods that the client sends again or not, the keepalive and the IDLE channel. They also cover a GOAWAY, the close, the checks and the manifestations. Seven scenarios replay against the document of the client. One test sends calls through grpc-js to a server of the loopback.
|
|
647
741
|
- **F6 for Redis.** The fault matrix crosses each manifestation (a refusal, a frozen process, a black hole, a death without a close, and an app stall), each gating posture, two timings and two jitters. That is 60 cases on the fake. Each case holds the trip and the release of its policy to `failSpan` and `recoverSpan`. Five more cases shut the service down during each manifestation, and each one exits 0.
|
|
648
742
|
- **The timers.** These tests use a fake clock, and they cover the hooks of the heartbeat and its two kinds of ping. A property test holds the death of a silent peer to `detectionTime` in 300 seeded cases. Another one compares the heartbeat with a WebSocket heartbeat that sends one ping at a time, on 300 schedules of pongs. The backoff gives the delays of three earlier backoffs, number for number, and each delay is in its band.
|
|
649
743
|
- **The entries.** The timer entries reach no other package, no `node:` module and no zod. No entry of the service reaches zod, also through `quantity` and the replay of the algebra. The root reaches no `node:` module. The HTTP edge reaches only `node:http`, `node:net` and `quantity`. The worker loop and the queue drain reach only `quantity`.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as Clock } from "./clock-mVqhXD0b.js";
|
|
2
2
|
import { c as LimiterSpec } from "./policy-G4QJ1ZZq.js";
|
|
3
|
-
import { B as
|
|
3
|
+
import { B as Check, E as CheckFn, G as ExitCodes, H as CooperativeFloor, I as Trace, J as MessageTrigger, P as Outcome, Q as ServiceDescription, St as ProcessTrigger, T as StartOptions, U as Coupling, W as Dependency, Y as Phase, Z as RepeatSignal, d as TransportImpl, gt as ExitTrigger, it as Timing, jt as Operation, n as HealthServer, nt as Poll, o as PhaseWork, q as Gate, r as Lifecycle, s as RunOptions, t as DependencyHandle, ut as OperationOf, x as Health } from "./lifecycle-CMedxaQd.js";
|
|
4
4
|
import { Extent, Quantity } from "@mark1russell7/quantity";
|
|
5
5
|
//#region src/profiles.d.ts
|
|
6
6
|
/**
|
|
@@ -208,4 +208,4 @@ interface ServiceBuilder {
|
|
|
208
208
|
declare const service: (name: string) => ServiceBuilder;
|
|
209
209
|
//#endregion
|
|
210
210
|
export { WatchdogSpec as a, Profile as c, kubernetes as d, localDev as f, Watchdog as i, daemon as l, ServiceBuilder as n, watchdog as o, service as r, PodTiming as s, ControllerBuilder as t, ephemeral as u };
|
|
211
|
-
//# sourceMappingURL=builder-
|
|
211
|
+
//# sourceMappingURL=builder-CsSO4LzB.d.ts.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { t as Backoff } from "./backoff-B-jGWVDm.js";
|
|
1
2
|
import { n as Clock } from "./clock-mVqhXD0b.js";
|
|
2
|
-
import {
|
|
3
|
-
import { n as ServiceBuilder } from "./builder-
|
|
3
|
+
import { $ as Step, B as Check, E as CheckFn, Q as ServiceDescription, W as Dependency, jt as Operation, nt as Poll, q as Gate, t as DependencyHandle, z as Recorder } from "./lifecycle-CMedxaQd.js";
|
|
4
|
+
import { n as ServiceBuilder } from "./builder-CsSO4LzB.js";
|
|
4
5
|
import { Extent, Quantity } from "@mark1russell7/quantity";
|
|
5
6
|
//#region src/client/meets.d.ts
|
|
6
7
|
/** A situation is what the connection did when the failure started: a command in flight, or idle. */
|
|
@@ -88,6 +89,13 @@ interface CheckOptions<S extends Step = ClientStep> {
|
|
|
88
89
|
readonly poll: Poll;
|
|
89
90
|
/** For each step, the policy that its check controls, or null for a check that only reports. A step that is absent has no check. */
|
|
90
91
|
readonly steps: Partial<Record<S, Gate | null>>;
|
|
92
|
+
/**
|
|
93
|
+
* With a catalog, the client gives a check for each step that it has (B19). The steps of `steps` are
|
|
94
|
+
* the nominated checks. Each other step reports only, and polls at the catalog poll. `true` is a poll
|
|
95
|
+
* of 30 s with the jitter and the timeout of `poll`. A nominated step that the client has no check
|
|
96
|
+
* for then fails the attach. Without a catalog, the client gives only the steps of `steps`.
|
|
97
|
+
*/
|
|
98
|
+
readonly catalog?: true | Poll | undefined;
|
|
91
99
|
}
|
|
92
100
|
/**
|
|
93
101
|
* These are the knobs that each client has, by the names of the ordering law. Each driver adds its
|
|
@@ -172,6 +180,48 @@ interface Client<S extends Step = ClientStep, J extends ClientJoin = ClientJoin>
|
|
|
172
180
|
/** This method gives the problems of the client in a description: a close that does not fit in its phase, for example. */
|
|
173
181
|
problems(description: ServiceDescription): string[];
|
|
174
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* A ready wait holds the calls that wait for a ready connection before their second try. A client
|
|
185
|
+
* that connects again by itself uses it: Redis and RabbitMQ.
|
|
186
|
+
*/
|
|
187
|
+
interface ReadyWait {
|
|
188
|
+
/** This method waits until the client is ready, for `within` milliseconds at most. It gives true when the client is ready. */
|
|
189
|
+
wait(within: number, signal?: AbortSignal): Promise<boolean>;
|
|
190
|
+
/** This method ends each wait with true. The client uses it when its connection is ready. */
|
|
191
|
+
wake(): void;
|
|
192
|
+
}
|
|
193
|
+
/** This function makes the ready wait of a client. The function `ready` tells if the client is ready. */
|
|
194
|
+
declare const readyWait: (clock: Clock, ready: () => boolean) => ReadyWait;
|
|
195
|
+
/** These are the knobs of a client that connects again by itself, after a delay that doubles. */
|
|
196
|
+
interface RetryKnobs {
|
|
197
|
+
/** This time is the first delay before a new try to connect. The delay doubles after each try. */
|
|
198
|
+
readonly retry_base: Quantity;
|
|
199
|
+
/** This time is the most that one delay can be, before its jitter. */
|
|
200
|
+
readonly retry_cap: Quantity;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* This function gives the backoff of the tries to connect: from `retry_base`, doubling to
|
|
204
|
+
* `retry_cap`, each with a jitter up to the base. The client rounds each delay to a whole millisecond.
|
|
205
|
+
*/
|
|
206
|
+
declare const retryBackoff: (knobs: RetryKnobs) => Backoff;
|
|
207
|
+
/**
|
|
208
|
+
* A retry schedule holds the next try to connect, for a client that connects again by itself. It
|
|
209
|
+
* counts the tries since the last join. Each delay comes from the backoff, rounded to a whole millisecond.
|
|
210
|
+
*/
|
|
211
|
+
interface RetrySchedule {
|
|
212
|
+
/** This count is the number of tries since the last reset. */
|
|
213
|
+
readonly tries: number;
|
|
214
|
+
/** This method counts one more try, and starts `due` after the delay of that try. It stops a try that waits. */
|
|
215
|
+
schedule(due: () => void): void;
|
|
216
|
+
/** This method stops the try that waits. The close uses it. */
|
|
217
|
+
cancel(): void;
|
|
218
|
+
/** This method sets the count of tries to zero. The client uses it at each join. */
|
|
219
|
+
reset(): void;
|
|
220
|
+
}
|
|
221
|
+
/** This function makes the retry schedule of a client, from its backoff and its random numbers. RabbitMQ and WebSocket use it. */
|
|
222
|
+
declare const retrySchedule: (clock: Clock, backoff: Backoff, random: () => number) => RetrySchedule;
|
|
223
|
+
/** This function gives the problems of the retry knobs: the cap must not be below the base. */
|
|
224
|
+
declare const retryProblems: (name: string, knobs: RetryKnobs) => string[];
|
|
175
225
|
/**
|
|
176
226
|
* This poll is a poll of the checks to start from: each 5 s with a jitter of 20 %, and a timeout of
|
|
177
227
|
* 4 s (B6, O12). Its slowest poll is 4 s + 5 s × 1.2 = 10 s, the slowest poll of the cells of O13.
|
|
@@ -179,5 +229,5 @@ interface Client<S extends Step = ClientStep, J extends ClientJoin = ClientJoin>
|
|
|
179
229
|
*/
|
|
180
230
|
declare const STARTING_POLL: Poll;
|
|
181
231
|
//#endregion
|
|
182
|
-
export {
|
|
183
|
-
//# sourceMappingURL=core-
|
|
232
|
+
export { MANIFESTATIONS as C, firstDetector as D, Situation as E, unwatched as O, Detector as S, Meeting as T, Sent as _, ClientKnobs as a, retryProblems as b, ClientSpec as c, Factory as d, ReadyWait as f, SendOptions as g, STARTING_POLL as h, ClientJoin as i, ClientStep as l, RetrySchedule as m, CheckOptions as n, ClientOptions as o, RetryKnobs as p, Client as r, ClientSocket as s, Attempt as t, DialFn as u, readyWait as v, Manifestation as w, retrySchedule as x, retryBackoff as y };
|
|
233
|
+
//# sourceMappingURL=core-D8iXeoE4.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import "./core-D8iXeoE4.js";
|
|
2
|
+
//#region src/client/dial.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* A judge reads the bytes that the server sent so far. It gives null for a good answer, an error for
|
|
5
|
+
* a bad answer, or "more" when it must wait for more bytes.
|
|
6
|
+
*/
|
|
7
|
+
type Judge = (received: Buffer) => Error | null | "more";
|
|
8
|
+
/**
|
|
9
|
+
* This function makes a judge of the status line of an HTTP/1.1 answer. The judge waits for the end
|
|
10
|
+
* of the line, in the first 8 KiB. Then `accept` reads the status code, and gives null for a good status or an error.
|
|
11
|
+
* The HTTP client accepts each status. The WebSocket client accepts only 101.
|
|
12
|
+
*/
|
|
13
|
+
declare const statusLineJudge: (accept: (status: number, line: string) => Error | null) => Judge;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { statusLineJudge as n, Judge as t };
|
|
16
|
+
//# sourceMappingURL=dial-DJolDmOK.d.ts.map
|
package/build/grpc.d.ts
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { jt as Operation, nt as Poll } from "./lifecycle-CMedxaQd.js";
|
|
2
|
+
import { C as MANIFESTATIONS, D as firstDetector, E as Situation, O as unwatched, S as Detector, T as Meeting, _ as Sent, a as ClientKnobs, b as retryProblems, c as ClientSpec, d as Factory, f as ReadyWait, g as SendOptions, h as STARTING_POLL, i as ClientJoin, l as ClientStep, n as CheckOptions, o as ClientOptions, p as RetryKnobs, r as Client, s as ClientSocket, t as Attempt, u as DialFn, v as readyWait, w as Manifestation } from "./core-D8iXeoE4.js";
|
|
3
|
+
import { t as Judge } from "./dial-DJolDmOK.js";
|
|
4
|
+
import { Extent, Quantity } from "@mark1russell7/quantity";
|
|
5
|
+
import { Machine } from "@mark1russell7/algebra";
|
|
6
|
+
//#region src/grpc/connection.d.ts
|
|
7
|
+
/** A state is the connectivity state of a channel of grpc-js, by the names of its enum `connectivityState`. */
|
|
8
|
+
type GrpcState = "IDLE" | "CONNECTING" | "READY" | "TRANSIENT_FAILURE" | "SHUTDOWN";
|
|
9
|
+
/** These states are in the sequence of the enum of grpc-js: the index of a state is its value. */
|
|
10
|
+
export declare const GRPC_STATES: readonly GrpcState[];
|
|
11
|
+
/** A status is the end of one call: its code (0 is OK) and its details. */
|
|
12
|
+
interface GrpcStatus {
|
|
13
|
+
readonly code: number;
|
|
14
|
+
readonly details: string;
|
|
15
|
+
}
|
|
16
|
+
/** A call handle stops one call in flight. The grpc-js driver then writes RST_STREAM with the code CANCEL. */
|
|
17
|
+
interface GrpcCallHandle {
|
|
18
|
+
cancel(): void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A channel is the part of a `Client` of grpc-js 1.14 that the wrapper uses. A fake for tests has
|
|
22
|
+
* each part too. Thus the package depends on no type of grpc-js.
|
|
23
|
+
*/
|
|
24
|
+
interface GrpcChannel {
|
|
25
|
+
/** This method gives the state of the channel. True also starts a connect when the channel is IDLE. */
|
|
26
|
+
state(connect: boolean): GrpcState;
|
|
27
|
+
/** This method starts `changed` one time, when the state of the channel is no longer `current`. */
|
|
28
|
+
watch(current: GrpcState, changed: () => void): void;
|
|
29
|
+
/**
|
|
30
|
+
* This method sends one unary call: the method path and the bytes of its request message. `done`
|
|
31
|
+
* gets the status of the call, and the bytes of the response message when the status is OK. The
|
|
32
|
+
* call ends at `timeout` milliseconds with DEADLINE_EXCEEDED, and grpc-js sends the header `grpc-timeout`.
|
|
33
|
+
*/
|
|
34
|
+
unary(method: string, request: Buffer, metadata: Readonly<Record<string, string>>, timeout: number, done: (status: GrpcStatus, response: Buffer | undefined) => void): GrpcCallHandle;
|
|
35
|
+
/** This method closes the channel. Its state becomes SHUTDOWN, and it does not connect again. */
|
|
36
|
+
close(): void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* These are the options of the channel that the wrapper gives `new Client(target, credentials, options)`.
|
|
40
|
+
* Each time comes from the declaration, in milliseconds.
|
|
41
|
+
*/
|
|
42
|
+
interface GrpcChannelOptions {
|
|
43
|
+
/** The wrapper turns off the retries of grpc-js, the transparent retry too. Only the core decides a second send. */
|
|
44
|
+
readonly "grpc.enable_retries": 0;
|
|
45
|
+
/** The wrapper reads no service config from the resolver. Thus no record of DNS changes the policy of a call. */
|
|
46
|
+
readonly "grpc.service_config_disable_resolution": 1;
|
|
47
|
+
/** This time is the interval of the HTTP/2 PING of keepalive. Without it, grpc-js sends no PING. */
|
|
48
|
+
readonly "grpc.keepalive_time_ms"?: number | undefined;
|
|
49
|
+
/** This time bounds the ACK of each PING. Without an ACK in this time, grpc-js ends the transport. */
|
|
50
|
+
readonly "grpc.keepalive_timeout_ms": number;
|
|
51
|
+
/** 1 sends the PING with no call in flight too. The server must permit that, or it answers with GOAWAY too_many_pings (O26). */
|
|
52
|
+
readonly "grpc.keepalive_permit_without_calls": 0 | 1;
|
|
53
|
+
/** This time with no call puts the channel in IDLE, and closes its connection. */
|
|
54
|
+
readonly "grpc.client_idle_timeout_ms": number;
|
|
55
|
+
/** This time is the first delay of grpc-js before a new try to connect. */
|
|
56
|
+
readonly "grpc.initial_reconnect_backoff_ms": number;
|
|
57
|
+
/** This time is the most that one delay of grpc-js can be, before its jitter of 20 %. */
|
|
58
|
+
readonly "grpc.max_reconnect_backoff_ms": number;
|
|
59
|
+
}
|
|
60
|
+
/** These are the arguments of `new Client(target, credentials, options)`. The credentials are insecure: the client speaks h2c. */
|
|
61
|
+
interface GrpcConnectOptions {
|
|
62
|
+
readonly target: string;
|
|
63
|
+
readonly options: GrpcChannelOptions;
|
|
64
|
+
}
|
|
65
|
+
/** A channel factory makes one channel from its options. The channel connects later, when the wrapper asks it. */
|
|
66
|
+
type GrpcFactory = Factory<GrpcConnectOptions, GrpcChannel>;
|
|
67
|
+
/** This type is the part of a `Client` of grpc-js 1.14 that the adapter uses. */
|
|
68
|
+
interface GrpcDriverClient {
|
|
69
|
+
getChannel(): {
|
|
70
|
+
getConnectivityState(connect: boolean): number;
|
|
71
|
+
watchConnectivityState(current: number, deadline: number, callback: (error?: Error) => void): void;
|
|
72
|
+
};
|
|
73
|
+
makeUnaryRequest(method: string, serialize: (value: Buffer) => Buffer, deserialize: (bytes: Buffer) => Buffer, argument: Buffer, metadata: unknown, options: {
|
|
74
|
+
readonly deadline: number;
|
|
75
|
+
}, callback: (error: {
|
|
76
|
+
readonly code?: number;
|
|
77
|
+
readonly details?: string;
|
|
78
|
+
readonly message?: string;
|
|
79
|
+
} | null, value?: Buffer) => void): GrpcCallHandle;
|
|
80
|
+
close(): void;
|
|
81
|
+
}
|
|
82
|
+
/** This type is the part of the module of grpc-js that the adapter uses. */
|
|
83
|
+
interface GrpcDriver {
|
|
84
|
+
readonly Client: new (target: string, credentials: unknown, options: GrpcChannelOptions) => GrpcDriverClient;
|
|
85
|
+
readonly credentials: {
|
|
86
|
+
createInsecure(): unknown;
|
|
87
|
+
};
|
|
88
|
+
readonly Metadata: new () => {
|
|
89
|
+
add(key: string, value: string): void;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* This function adapts a `Client` of grpc-js to a channel. The deadline of grpc-js is a time of the
|
|
94
|
+
* wall clock, thus the adapter adds the timeout to `Date.now()`.
|
|
95
|
+
*/
|
|
96
|
+
export declare const adaptGrpc: (grpc: GrpcDriver, client: GrpcDriverClient) => GrpcChannel;
|
|
97
|
+
/**
|
|
98
|
+
* This factory makes a `Client` of grpc-js. It loads grpc-js only when a client connects, thus a
|
|
99
|
+
* service that does not use gRPC does not need it. The specifier is a value, thus the package needs no types of grpc-js.
|
|
100
|
+
*/
|
|
101
|
+
export declare const nodeGrpc: GrpcFactory;
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/grpc/client.d.ts
|
|
104
|
+
/**
|
|
105
|
+
* These are the knobs of the client, each a time, by the names of the ordering law and of the gRPC
|
|
106
|
+
* cells. The runtime has no defaults, thus each knob is necessary. The constant
|
|
107
|
+
* `GRPC_CLIENT_STARTING_KNOBS` gives a declaration from the gRPC cells. The knobs that each client has come from the core.
|
|
108
|
+
*/
|
|
109
|
+
interface GrpcKnobs extends ClientKnobs, RetryKnobs {
|
|
110
|
+
/** This time bounds the wait of the startup for a ready channel. The grpc-js driver has no connect timeout, and the wrapper cannot stop one connect. */
|
|
111
|
+
readonly connect_bound: Quantity;
|
|
112
|
+
/** This time is the deadline of each call, from its start. A second try ends in the same bound. The grpc-js driver sends it as `grpc-timeout`. */
|
|
113
|
+
readonly request_timeout: Quantity;
|
|
114
|
+
/** This time is the interval of the HTTP/2 PING of keepalive (`grpc.keepalive_time_ms`). "infinite" sends no PING, as grpc-js does at its defaults. */
|
|
115
|
+
readonly keepalive_time: Extent;
|
|
116
|
+
/** This time bounds the ACK of each PING (`grpc.keepalive_timeout_ms`). With no ACK, grpc-js ends the transport. */
|
|
117
|
+
readonly keepalive_timeout: Quantity;
|
|
118
|
+
/** This time with no call puts the channel in IDLE and closes its connection (`grpc.client_idle_timeout_ms`). The client then connects again. */
|
|
119
|
+
readonly client_idle_timeout: Quantity;
|
|
120
|
+
/**
|
|
121
|
+
* This time is the shortest interval of the PING that the server permits: `MinTime` of the
|
|
122
|
+
* enforcement policy of grpc-go. A shorter keepalive gets GOAWAY too_many_pings (O26). It is a fact of the server, not a knob of the client.
|
|
123
|
+
*/
|
|
124
|
+
readonly server_keepalive_min_time: Quantity;
|
|
125
|
+
/** This time is when the server or a proxy ends an idle connection with GOAWAY, or "infinite". The client must close first (O01). */
|
|
126
|
+
readonly server_idle_close: Extent;
|
|
127
|
+
/** This time is the first delay of grpc-js before a new try to connect (`grpc.initial_reconnect_backoff_ms`). */
|
|
128
|
+
readonly retry_base: Quantity;
|
|
129
|
+
/** This time is the most that one delay of grpc-js can be, before its jitter of 20 % (`grpc.max_reconnect_backoff_ms`). */
|
|
130
|
+
readonly retry_cap: Quantity;
|
|
131
|
+
/** The grpc-js driver sets no TCP keepalive on its socket: the PING of `keepalive_time` is its keepalive. Thus this knob must be "infinite". */
|
|
132
|
+
readonly keepalive_idle: Extent;
|
|
133
|
+
/** The client does not replace its connection at an age, thus this knob must be "infinite". */
|
|
134
|
+
readonly max_connection_age: Extent;
|
|
135
|
+
/** This time bounds the close at the shutdown: the calls in flight. At the bound, the client cancels each call, then closes the channel. */
|
|
136
|
+
readonly close_bound: Quantity;
|
|
137
|
+
}
|
|
138
|
+
/** A gRPC client spec is the declaration of one gRPC client: where it connects, and its knobs. */
|
|
139
|
+
interface GrpcClientSpec extends ClientSpec<GrpcKnobs> {
|
|
140
|
+
/**
|
|
141
|
+
* True sends the PING of keepalive with no call in flight too (`grpc.keepalive_permit_without_calls`).
|
|
142
|
+
* The server must permit that (`PermitWithoutStream` of grpc-go), or it answers with GOAWAY too_many_pings (O26).
|
|
143
|
+
*/
|
|
144
|
+
readonly keepaliveWithoutCalls: boolean;
|
|
145
|
+
/** These headers go with each call, for example `authorization`. The metadata of a call adds to them. */
|
|
146
|
+
readonly metadata?: Readonly<Record<string, string>> | undefined;
|
|
147
|
+
/** This name is the service that the round-trip check asks the health service about. The default is "", the whole server. */
|
|
148
|
+
readonly healthService?: string | undefined;
|
|
149
|
+
/**
|
|
150
|
+
* These operations are the methods of the service, by their full path, with their idempotency. The
|
|
151
|
+
* client sends again only a method that this table names as idempotent. `grpcOperations` makes the
|
|
152
|
+
* table from the `idempotency_level` of each method in its proto.
|
|
153
|
+
*/
|
|
154
|
+
readonly operations?: ClientSpec<GrpcKnobs>["operations"];
|
|
155
|
+
}
|
|
156
|
+
/** These options make a client. Without them, it uses grpc-js, the real clock, and a dial with the HTTP/2 preface. */
|
|
157
|
+
type GrpcClientOptions = ClientOptions<GrpcFactory>;
|
|
158
|
+
/**
|
|
159
|
+
* A join is one generation of the client: each time that its channel becomes READY (D1, D2). The
|
|
160
|
+
* grpc-js driver gives no socket of its transport, thus the ends of the socket are null.
|
|
161
|
+
*/
|
|
162
|
+
interface GrpcJoin extends ClientJoin {
|
|
163
|
+
/** This text is the target of the channel. */
|
|
164
|
+
readonly target: string;
|
|
165
|
+
}
|
|
166
|
+
/** These options tell how the client sends one call. */
|
|
167
|
+
interface GrpcCallOptions extends SendOptions {
|
|
168
|
+
/** These headers go with this call, after the metadata of the spec. */
|
|
169
|
+
readonly metadata?: Readonly<Record<string, string>> | undefined;
|
|
170
|
+
}
|
|
171
|
+
/** A serving status is the status of a HealthCheckResponse of the health service (grpc.health.v1). */
|
|
172
|
+
type GrpcServingStatus = "UNKNOWN" | "SERVING" | "NOT_SERVING" | "SERVICE_UNKNOWN";
|
|
173
|
+
/** A gRPC client is a dependency of a service: its declaration, its handle, its checks and its calls. */
|
|
174
|
+
interface GrpcClient extends Client<ClientStep, GrpcJoin> {
|
|
175
|
+
/** This text is the state of the client, as `GRPC_CLIENT_MACHINE` names it. */
|
|
176
|
+
readonly status: string;
|
|
177
|
+
/**
|
|
178
|
+
* This method sends one unary call, and waits for its status. `request` holds the bytes of the
|
|
179
|
+
* request message, and an OK status gives the bytes of the response message. The client sends again
|
|
180
|
+
* only an idempotent method, one time at most, after an outcome that is not certain.
|
|
181
|
+
*/
|
|
182
|
+
call(method: string, request: Buffer, options?: GrpcCallOptions): Promise<Sent<Buffer>>;
|
|
183
|
+
/** This method sends one Check of the health service (grpc.health.v1), and gives the serving status of the reply. */
|
|
184
|
+
health(service?: string, options?: SendOptions): Promise<Sent<GrpcServingStatus>>;
|
|
185
|
+
}
|
|
186
|
+
/** The names of the status codes of gRPC, by their value. */
|
|
187
|
+
export declare const GRPC_CODES: readonly ["OK", "CANCELLED", "UNKNOWN", "INVALID_ARGUMENT", "DEADLINE_EXCEEDED", "NOT_FOUND", "ALREADY_EXISTS", "PERMISSION_DENIED", "RESOURCE_EXHAUSTED", "FAILED_PRECONDITION", "ABORTED", "OUT_OF_RANGE", "UNIMPLEMENTED", "INTERNAL", "UNAVAILABLE", "DATA_LOSS", "UNAUTHENTICATED"];
|
|
188
|
+
/** This function gives the name of a status code, for example "UNAVAILABLE". */
|
|
189
|
+
export declare const codeName: (code: number) => string;
|
|
190
|
+
/**
|
|
191
|
+
* This function gives the outcome of one call from its status:
|
|
192
|
+
* - OK is `ok`.
|
|
193
|
+
* - A code that tells that the server refused the call is a certain error: `reply` is true.
|
|
194
|
+
* - A status that tells that the call did not leave the client is a certain error with `reply` false.
|
|
195
|
+
* - Each other status is indeterminate: CANCELLED, UNKNOWN, DEADLINE_EXCEEDED, RESOURCE_EXHAUSTED,
|
|
196
|
+
* INTERNAL, UNAVAILABLE and DATA_LOSS can come after the server applied the call.
|
|
197
|
+
*/
|
|
198
|
+
export declare const grpcOutcome: (status: GrpcStatus, response: Buffer | undefined) => Attempt<Buffer>;
|
|
199
|
+
/** This method is the Check of the health service. Its request names a service, and its response gives a serving status. */
|
|
200
|
+
export declare const HEALTH_CHECK = "/grpc.health.v1.Health/Check";
|
|
201
|
+
/** These operations are in each table: the Check of the health service has no side effects. */
|
|
202
|
+
export declare const GRPC_OPERATIONS: Readonly<Record<string, Operation>>;
|
|
203
|
+
/** An idempotency level is the option `idempotency_level` of a method in its proto (descriptor.proto). */
|
|
204
|
+
type GrpcIdempotencyLevel = "IDEMPOTENCY_UNKNOWN" | "NO_SIDE_EFFECTS" | "IDEMPOTENT";
|
|
205
|
+
/**
|
|
206
|
+
* This function makes a table of operations from the idempotency level of each method, by its full
|
|
207
|
+
* path. NO_SIDE_EFFECTS and IDEMPOTENT are idempotent. IDEMPOTENCY_UNKNOWN, the default of a proto, is not.
|
|
208
|
+
*/
|
|
209
|
+
export declare const grpcOperations: (levels: Readonly<Record<string, GrpcIdempotencyLevel>>) => Record<string, Operation>;
|
|
210
|
+
/** This function gives the bytes of a HealthCheckRequest. The service "" is the whole server, and its message is empty. */
|
|
211
|
+
export declare const healthRequest: (service: string) => Buffer;
|
|
212
|
+
/** This function gives the status of a HealthCheckResponse, or null when the bytes are not one. An empty message is UNKNOWN. */
|
|
213
|
+
export declare const healthStatus: (bytes: Buffer) => GrpcServingStatus | null;
|
|
214
|
+
/** This function gives the problems of a spec: the knobs that the client cannot use. */
|
|
215
|
+
export declare const specProblems: (name: string, spec: GrpcClientSpec) => string[];
|
|
216
|
+
/** This function gives the target of a channel from a spec: the host and the port, for the DNS resolver of grpc-js. */
|
|
217
|
+
export declare const grpcTarget: (spec: Pick<GrpcClientSpec, "host" | "port">) => string;
|
|
218
|
+
/**
|
|
219
|
+
* This function gives the arguments of `new Client` from a spec. Each timer of grpc-js comes from the
|
|
220
|
+
* declaration. The retries of grpc-js are off, and the resolver gives no service config.
|
|
221
|
+
*/
|
|
222
|
+
export declare const grpcOptions: (spec: GrpcClientSpec) => GrpcConnectOptions;
|
|
223
|
+
/** These are the bytes of the dial: the connection preface of the client (RFC 9113 §3.4), and a SETTINGS frame with no setting. */
|
|
224
|
+
export declare const HTTP2_PREFACE: Buffer;
|
|
225
|
+
/**
|
|
226
|
+
* This judge reads the first frame of the server. Only a SETTINGS frame on stream 0, with no ACK,
|
|
227
|
+
* passes: RFC 9113 §3.4 makes it the first frame of an HTTP/2 server. An HTTP/1.1 server answers with a status line.
|
|
228
|
+
*/
|
|
229
|
+
export declare const settingsJudge: Judge;
|
|
230
|
+
/** This dial opens a new TCP connection, sends the HTTP/2 preface, and waits for the SETTINGS frame of the server. The dial then destroys its socket. */
|
|
231
|
+
export declare const grpcDial: DialFn;
|
|
232
|
+
/**
|
|
233
|
+
* This function makes a gRPC client, a dependency of a service over grpc-js 1.14.
|
|
234
|
+
* - It has one channel for its life. Each time that the channel becomes READY is one generation.
|
|
235
|
+
* - The grpc-js driver connects again by itself, after its own backoff. The client connects an IDLE channel again at once.
|
|
236
|
+
* - A call is one unary call, until its status. Its deadline is the time that is left in `request_timeout`.
|
|
237
|
+
* - It tells the outcome of a call in three values from its status code (C8).
|
|
238
|
+
* - The retries of grpc-js are off, thus only the core sends a call again.
|
|
239
|
+
* - Its keepalive is the HTTP/2 PING of grpc-js. It records the target of each generation (D1).
|
|
240
|
+
*
|
|
241
|
+
* These parts come from the core of the clients: the outcomes, the second try and the wait for a ready client.
|
|
242
|
+
* The calls in flight, the bounded close and the checks come from the core too. This entry gives what grpc-js does in its own way.
|
|
243
|
+
*/
|
|
244
|
+
export declare const grpcClient: (name: string, spec: GrpcClientSpec, options?: GrpcClientOptions) => GrpcClient;
|
|
245
|
+
//#endregion
|
|
246
|
+
//#region src/grpc/machine.d.ts
|
|
247
|
+
/**
|
|
248
|
+
* The gRPC client of the service as a `mark1russell7.machine/1` document. It is one channel of
|
|
249
|
+
* grpc-js 1.14 for the life of the client. Each READY of the channel is one generation. The states:
|
|
250
|
+
* - `ready`: the channel is READY, and the client sends each call. The keepalive sends a PING each keepalive_time.
|
|
251
|
+
* - `idle`: the transport ended, or the channel had no call in client_idle_timeout. The client connects again at once.
|
|
252
|
+
* - `failing`: the channel is in TRANSIENT_FAILURE. The grpc-js driver connects again after its backoff.
|
|
253
|
+
* - `closing`: the calls in flight, in `close_bound`. At the bound, each call gets RST_STREAM CANCEL.
|
|
254
|
+
*
|
|
255
|
+
* A test records the transitions of the client and replays them against this document.
|
|
256
|
+
*/
|
|
257
|
+
export declare const GRPC_CLIENT_MACHINE: Machine;
|
|
258
|
+
//#endregion
|
|
259
|
+
//#region src/grpc/meets.d.ts
|
|
260
|
+
/**
|
|
261
|
+
* This function gives the manifestations that a gRPC client can meet, and the detectors of each,
|
|
262
|
+
* from its knobs. The gRPC cells measured them on grpc-js 1.14.6:
|
|
263
|
+
* - At its defaults, grpc-js has no detector: no keepalive, no deadline, and no TCP keepalive.
|
|
264
|
+
* - A reset gave each call ECONNRESET in 1.1 ms to 1.4 ms. The FIN of a stopped server ended an idle connection in 43 µs.
|
|
265
|
+
* - The keepalive ended a silent transport at keepalive_time + keepalive_timeout: 80.012 s at 60 s
|
|
266
|
+
* against etcd, and 320.005 s at 300 s against grpc-go (DP24).
|
|
267
|
+
* - Without `keepaliveWithoutCalls`, grpc-js sends a PING only with a call in flight.
|
|
268
|
+
* - At client_idle_timeout, the channel goes IDLE, and the client connects again. A server that does
|
|
269
|
+
* not answer then keeps the channel out of READY.
|
|
270
|
+
*/
|
|
271
|
+
export declare const grpcMeetings: (name: string, knobs: GrpcKnobs, withoutCalls: boolean) => Meeting[];
|
|
272
|
+
//#endregion
|
|
273
|
+
//#region src/grpc/starting.d.ts
|
|
274
|
+
/**
|
|
275
|
+
* This poll is the poll of the checks that `GRPC_CLIENT_STARTING_KNOBS` fits. It is `STARTING_POLL` of
|
|
276
|
+
* the core: each 5 s with a jitter of 20 %, and a timeout of 4 s (B6, O12). The poll does not depend on the driver.
|
|
277
|
+
*/
|
|
278
|
+
export declare const GRPC_CLIENT_STARTING_POLL: Poll;
|
|
279
|
+
/**
|
|
280
|
+
* This value tells if the keepalive sends a PING with no call in flight, to start from: false. The
|
|
281
|
+
* grpc-go server refuses such a PING at its defaults (`PermitWithoutStream` false). It answers with GOAWAY too_many_pings (O26).
|
|
282
|
+
*/
|
|
283
|
+
export declare const GRPC_CLIENT_STARTING_WITHOUT_CALLS: boolean;
|
|
284
|
+
/**
|
|
285
|
+
* These knobs are a declaration to start from, from what the gRPC cells measured on grpc-js 1.14.6.
|
|
286
|
+
* The runtime has no defaults: a service gives these knobs, or its own. Each value holds the borders that the cells measured:
|
|
287
|
+
* - `connect_bound` 5 s: the connect timeout of DP44. The grpc-js driver has no connect timeout, thus this bounds the wait of the startup.
|
|
288
|
+
* - `request_timeout` 9.5 s: in the slowest poll of 10 s (O13). In DP44 a deadline of 4 s ended each
|
|
289
|
+
* call at 4.003 s to 4.004 s. The race of the two deadlines gave CANCELLED to 2 to 4 calls of 11.
|
|
290
|
+
* - `keepalive_time` 300 s and `keepalive_timeout` 20 s: DP24. The PING must not come before the
|
|
291
|
+
* `MinTime` of the server, 5 min at the defaults of grpc-go (O26). The transport ended at 320.005 s.
|
|
292
|
+
* Against etcd, with a `MinTime` of 5 s, 60 s ended it at 80.012 s. A PING each 4 s against 5 s got GOAWAY at the 4th PING.
|
|
293
|
+
* - `server_keepalive_min_time` 300 s: the `MinTime` of grpc-go v1.84.0 at its defaults.
|
|
294
|
+
* - `client_idle_timeout` 60 s and `server_idle_close` 75 s: the proxies of the cells sent GOAWAY to an idle connection.
|
|
295
|
+
* They did that at 75 s (nginx), 180 s (Traefik), 300 s (Caddy) and 1 h (Envoy). The client closes first (O01).
|
|
296
|
+
* The default of grpc-js is 30 min.
|
|
297
|
+
* - `retry_base` 1 s: the first backoff of grpc-js in T07, with no jitter. `retry_cap` 4 s: the most
|
|
298
|
+
* delay is 4.8 s with the jitter of 20 %, in the slowest poll of 10 s. The default of grpc-js is 120 s.
|
|
299
|
+
* - `keepalive_idle` "infinite": grpc-js sets no TCP keepalive, and the PING is its keepalive.
|
|
300
|
+
* - `max_connection_age` "infinite": the client does not replace its connection at an age.
|
|
301
|
+
* - `close_bound` 2 s: the calls in flight, then RST_STREAM CANCEL for each call that stays.
|
|
302
|
+
* - `retrans_giveup_time` 924.6 s: the give-up of Linux at `tcp_retries2 = 15`.
|
|
303
|
+
*/
|
|
304
|
+
export declare const GRPC_CLIENT_STARTING_KNOBS: GrpcKnobs;
|
|
305
|
+
//#endregion
|
|
306
|
+
export { type Attempt, type CheckOptions, type Client, type ClientJoin, type ClientKnobs, type ClientOptions, type ClientSocket, type ClientSpec, type ClientStep, type Detector, type DialFn, type Factory, type GrpcCallHandle, type GrpcCallOptions, type GrpcChannel, type GrpcChannelOptions, type GrpcClient, type GrpcClientOptions, type GrpcClientSpec, type GrpcConnectOptions, type GrpcFactory, type GrpcIdempotencyLevel, type GrpcJoin, type GrpcKnobs, type GrpcServingStatus, type GrpcState, type GrpcStatus, type Judge, MANIFESTATIONS, type Manifestation, type Meeting, type ReadyWait, type RetryKnobs, STARTING_POLL, type SendOptions, type Sent, type Situation, firstDetector, readyWait, retryProblems, unwatched };
|
|
307
|
+
//# sourceMappingURL=grpc.d.ts.map
|