@mark1russell7/machines 0.3.15 → 0.3.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/build/index.js CHANGED
@@ -1,5 +1,1238 @@
1
1
  import { machineSchema } from "@mark1russell7/algebra";
2
2
  import { z } from "zod";
3
+ //#region src/grpc/grpc-go-server.ts
4
+ const AT$9 = "grpc-go v1.84.0";
5
+ const GO = "go1.27.2 src/net";
6
+ const ETCD = "etcd v3.6.15";
7
+ /** These are the facts of the transport of grpc-go, for each server on it. */
8
+ const TRANSPORT = [
9
+ {
10
+ ref: `${AT$9} internal/transport/defaults.go:31-40 the server keepalive: Time 2 h, Timeout 20 s. MinTime of the policy 5 min. MaxConnectionIdle, Age and AgeGrace infinite`,
11
+ rung: "implemented"
12
+ },
13
+ {
14
+ ref: `${AT$9} internal/transport/http2_server.go:226-253 the defaults of the parameters, a jitter of 10 % on MaxConnectionAge, and TCP_USER_TIMEOUT = Timeout when Time is not infinite`,
15
+ rung: "implemented"
16
+ },
17
+ {
18
+ ref: `${AT$9} internal/syscall/syscall_linux.go:71-90 SetTCPUserTimeout acts only on a *net.TCPConn. On any other net.Conn it does nothing`,
19
+ rung: "implemented"
20
+ },
21
+ {
22
+ ref: `${AT$9} internal/transport/http2_server.go:1197-1286 keepalive(): a PING after Time with no read, and Close when no read comes for Timeout after it. MaxConnectionIdle and MaxConnectionAge drain with GOAWAY, and AgeGrace closes`,
23
+ rung: "implemented"
24
+ },
25
+ {
26
+ ref: `${AT$9} internal/transport/http2_server.go:881-933 handlePing: a PING less than MinTime after the last one is a strike, and with no stream open and PermitWithoutStream false, less than 2 h. The third strike sends GOAWAY ENHANCE_YOUR_CALM too_many_pings and closes the connection`,
27
+ rung: "implemented"
28
+ },
29
+ {
30
+ ref: `${AT$9} internal/transport/http2_server.go:279-281, :1064, :1132, :1176 each write of headers, a status or data by the server clears the strikes`,
31
+ rung: "implemented"
32
+ },
33
+ {
34
+ ref: `${AT$9} internal/transport/http2_server.go:1291-1310 Close closes the net.Conn: a FIN, or a reset when bytes are unread`,
35
+ rung: "implemented"
36
+ },
37
+ {
38
+ ref: `${AT$9} internal/transport/http2_server.go:536-537, :603-615 a call with the header grpc-timeout gets a timer of that timeout from the read of its headers. Its end closes the stream with RST_STREAM CANCEL, and the context of the handler ends`,
39
+ rung: "implemented"
40
+ },
41
+ {
42
+ ref: `${AT$9} server.go:192, :1000-1009 a deadline of 120 s for the handshake of each new connection (ConnectionTimeout)`,
43
+ rung: "implemented"
44
+ },
45
+ {
46
+ ref: `${AT$9} server.go:894-905 the comment of grpc-go: Go sets a TCP keepalive of 15 s on each accepted connection`,
47
+ rung: "documented"
48
+ },
49
+ {
50
+ ref: `${GO}/dial.go:20-27 the defaults of the TCP keepalive of Go: 15 s idle, 15 s between probes, 9 probes`,
51
+ rung: "implemented"
52
+ },
53
+ {
54
+ ref: `${GO}/tcpsock_posix.go:158-164 and tcpsock.go:289-305 each accepted connection gets the KeepAlive of its ListenConfig: on, with the defaults of Go, when the caller gives none`,
55
+ rung: "implemented"
56
+ },
57
+ {
58
+ ref: `${GO}/tcpsock_unix.go:12-31 and tcpsockopt_unix.go:15-53 SetKeepAliveConfig sets SO_KEEPALIVE, TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT`,
59
+ rung: "implemented"
60
+ },
61
+ {
62
+ ref: "linux v6.6 net/ipv4/tcp_timer.c tcp_keepalive_timer: with TCP_USER_TIMEOUT set, the keepalive aborts at its first firing that is U after the last received segment, with a probe out. Thus at K + k·I, k = max(1, ceil((U − K) / I)), and TCP_KEEPCNT is not read",
63
+ rung: "implemented"
64
+ }
65
+ ];
66
+ /** This function gives the document of a server of grpc-go for one variant. */
67
+ const serverOf = (variant) => machineSchema.parse({
68
+ format: "mark1russell7.machine/1",
69
+ id: variant.id,
70
+ title: variant.title,
71
+ layer: "server",
72
+ version: variant.version,
73
+ conditions: variant.conditions,
74
+ sources: [...TRANSPORT, ...variant.sources],
75
+ states: {
76
+ "[none]": {
77
+ initial: true,
78
+ pseudo: true,
79
+ note: "Before the accept of the connection"
80
+ },
81
+ handshake: { note: "The accepted connection, until the preface and the SETTINGS of the client, with the deadline of ConnectionTimeout" },
82
+ idle: { note: "A ready transport with no stream open. The keepalive of the server runs" },
83
+ active: { note: "One or more streams open, for example a call that the handler holds" },
84
+ draining: { note: "After a GOAWAY of the server: no new stream, and the open streams end" },
85
+ ended: {
86
+ final: true,
87
+ note: "The connection closed"
88
+ }
89
+ },
90
+ events: {
91
+ "local.accept": {
92
+ kind: "local",
93
+ note: "The listener accepts the connection, with the TCP keepalive of Go, and TCP_USER_TIMEOUT where it applies"
94
+ },
95
+ "rx.settings": {
96
+ kind: "rx",
97
+ note: "The preface and the first SETTINGS of the client"
98
+ },
99
+ "rx.frame": {
100
+ kind: "rx",
101
+ note: "Any frame of the client. The server keeps the time of its last read"
102
+ },
103
+ "rx.headers": {
104
+ kind: "rx",
105
+ note: "The headers of a new stream: a call"
106
+ },
107
+ "rx.ping": {
108
+ kind: "rx",
109
+ note: "A PING of the client. The server answers it, and checks it against its policy"
110
+ },
111
+ "rx.ping-strike-3": {
112
+ kind: "rx",
113
+ note: "The third PING that breaks the policy, with no write of the server since the first one"
114
+ },
115
+ "rx.ping-ack": {
116
+ kind: "rx",
117
+ note: "The ACK of a PING of the server"
118
+ },
119
+ "local.stream-end": {
120
+ kind: "local",
121
+ note: "The last open stream ends: its status goes out"
122
+ },
123
+ "timer.call-deadline": {
124
+ kind: "timer",
125
+ note: "The timeout of the header grpc-timeout of a call ends"
126
+ },
127
+ "tx.rst-stream": {
128
+ kind: "tx",
129
+ note: "RST_STREAM CANCEL of a stream, at the deadline of its call"
130
+ },
131
+ "app.stop": {
132
+ kind: "app",
133
+ note: "GracefulStop: a GOAWAY on each connection"
134
+ },
135
+ "peer.fin": {
136
+ kind: "peer",
137
+ note: "The client ends the connection: an end of file for the reader of the server"
138
+ },
139
+ "peer.rst": {
140
+ kind: "peer",
141
+ note: "A reset of the connection"
142
+ },
143
+ "socket.error": {
144
+ kind: "local",
145
+ note: "The socket fails with its own error: a reset, or a give-up of the kernel (ETIMEDOUT)"
146
+ },
147
+ "timer.connection-timeout": {
148
+ kind: "timer",
149
+ note: "No preface came before the deadline of the handshake"
150
+ },
151
+ "timer.keepalive": {
152
+ kind: "timer",
153
+ note: "No read for Time: the server sends a PING"
154
+ },
155
+ "timer.ping-timeout": {
156
+ kind: "timer",
157
+ note: "No read for Timeout after the PING"
158
+ },
159
+ "timer.max-idle": {
160
+ kind: "timer",
161
+ note: "No stream open for MaxConnectionIdle"
162
+ },
163
+ "timer.max-age": {
164
+ kind: "timer",
165
+ note: "The connection is MaxConnectionAge old"
166
+ },
167
+ "timer.grace": {
168
+ kind: "timer",
169
+ note: "AgeGrace after the GOAWAY of the age"
170
+ },
171
+ "tx.ping": {
172
+ kind: "tx",
173
+ note: "A PING of the keepalive of the server"
174
+ },
175
+ "tx.goaway": {
176
+ kind: "tx",
177
+ note: "A GOAWAY of the server"
178
+ },
179
+ "tx.fin": {
180
+ kind: "tx",
181
+ note: "The close of the net.Conn: a FIN"
182
+ }
183
+ },
184
+ knobs: {
185
+ keepalive_time: {
186
+ key: "keepalive.ServerParameters.Time",
187
+ scope: "server",
188
+ unit: "s",
189
+ default: 7200,
190
+ note: "defaults.go:38: 2 h. 0 is the default"
191
+ },
192
+ keepalive_timeout: {
193
+ key: "keepalive.ServerParameters.Timeout",
194
+ scope: "server",
195
+ unit: "s",
196
+ default: 20,
197
+ note: "defaults.go:39: the wait after the PING, and TCP_USER_TIMEOUT where it applies"
198
+ },
199
+ min_time: {
200
+ key: "keepalive.EnforcementPolicy.MinTime",
201
+ scope: "server",
202
+ unit: "s",
203
+ default: variant.minTime,
204
+ note: "the shortest interval between two PINGs of a client with a stream open"
205
+ },
206
+ permit_without_stream: {
207
+ key: "keepalive.EnforcementPolicy.PermitWithoutStream",
208
+ scope: "server",
209
+ unit: null,
210
+ default: 0,
211
+ note: "false: with no stream open, the shortest interval is 2 h"
212
+ },
213
+ no_stream_ping_interval: {
214
+ key: "defaultPingTimeout",
215
+ scope: "server",
216
+ unit: "s",
217
+ default: 7200,
218
+ note: "http2_server.go:883: a constant of grpc-go"
219
+ },
220
+ max_ping_strikes: {
221
+ key: "maxPingStrikes",
222
+ scope: "server",
223
+ unit: "count",
224
+ default: 2,
225
+ note: "http2_server.go:882: the GOAWAY comes at the strike after it"
226
+ },
227
+ max_connection_idle: {
228
+ key: "keepalive.ServerParameters.MaxConnectionIdle",
229
+ scope: "server",
230
+ unit: "s",
231
+ default: 0,
232
+ off: 0,
233
+ note: "defaults.go:35: infinite, and 0 is the default"
234
+ },
235
+ max_connection_age: {
236
+ key: "keepalive.ServerParameters.MaxConnectionAge",
237
+ scope: "server",
238
+ unit: "s",
239
+ default: 0,
240
+ off: 0,
241
+ note: "defaults.go:36: infinite. When set, a jitter of ±10 %"
242
+ },
243
+ max_connection_age_grace: {
244
+ key: "keepalive.ServerParameters.MaxConnectionAgeGrace",
245
+ scope: "server",
246
+ unit: "s",
247
+ default: 0,
248
+ off: 0,
249
+ note: "defaults.go:37: infinite"
250
+ },
251
+ connection_timeout: {
252
+ key: "grpc.ConnectionTimeout",
253
+ scope: "server",
254
+ unit: "s",
255
+ default: 120,
256
+ note: "server.go:192"
257
+ },
258
+ call_timeout: {
259
+ key: "the header grpc-timeout of a call",
260
+ scope: "call",
261
+ unit: "s",
262
+ default: 0,
263
+ off: 0,
264
+ note: "The client gives it: the time left to its deadline when it sends the headers. No timeout when the call has no deadline"
265
+ },
266
+ listener_keepidle: {
267
+ key: "the TCP keepalive idle of an accepted connection",
268
+ scope: "server",
269
+ unit: "s",
270
+ default: variant.listenerIdle,
271
+ note: variant.note
272
+ },
273
+ listener_keepintvl: {
274
+ key: "the TCP keepalive interval of an accepted connection",
275
+ scope: "server",
276
+ unit: "s",
277
+ default: 15,
278
+ note: "dial.go:24: the default of Go"
279
+ },
280
+ listener_keepcnt: {
281
+ key: "the TCP keepalive count of an accepted connection",
282
+ scope: "server",
283
+ unit: "count",
284
+ default: 9,
285
+ note: "dial.go:27: the default of Go"
286
+ },
287
+ sets_user_timeout: {
288
+ key: "TCP_USER_TIMEOUT reaches the socket",
289
+ scope: "server",
290
+ unit: "count",
291
+ default: variant.setsUserTimeout,
292
+ note: "1 when grpc-go gets the *net.TCPConn of the listener, else 0. A wrapper of the conn, as cmux, makes it 0 (syscall_linux.go:71-77). A count, thus the sets of the socket can read it"
293
+ },
294
+ slack: {
295
+ key: "the lateness of the scheduler of Go for one step",
296
+ scope: "process",
297
+ unit: "s",
298
+ default: .01,
299
+ note: "An assumption of this document, not a value of grpc-go"
300
+ },
301
+ hz: {
302
+ key: "CONFIG_HZ",
303
+ scope: "global",
304
+ unit: "Hz",
305
+ default: null,
306
+ note: "The build option of the kernel"
307
+ }
308
+ },
309
+ timers: {
310
+ connection_timeout: {
311
+ duration: {
312
+ knob: "connection_timeout",
313
+ unit: "s"
314
+ },
315
+ lateness: {
316
+ knob: "slack",
317
+ unit: "s"
318
+ },
319
+ arms: ["local.accept"],
320
+ cancels: ["rx.settings"],
321
+ fires: "timer.connection-timeout",
322
+ note: "server.go:1005-1009: a deadline of the conn for the handshake"
323
+ },
324
+ keepalive: {
325
+ duration: {
326
+ knob: "keepalive_time",
327
+ unit: "s"
328
+ },
329
+ lateness: {
330
+ knob: "slack",
331
+ unit: "s"
332
+ },
333
+ arms: [
334
+ "rx.settings",
335
+ "rx.frame",
336
+ "rx.ping-ack"
337
+ ],
338
+ fires: "timer.keepalive",
339
+ note: "http2_server.go:1252-1262: from the last read. The timer fires at Time and finds the last read, thus it sets itself again to Time after that read"
340
+ },
341
+ ping_timeout: {
342
+ duration: {
343
+ knob: "keepalive_timeout",
344
+ unit: "s"
345
+ },
346
+ lateness: {
347
+ knob: "slack",
348
+ unit: "s"
349
+ },
350
+ arms: ["tx.ping"],
351
+ cancels: ["rx.frame", "rx.ping-ack"],
352
+ fires: "timer.ping-timeout",
353
+ note: "http2_server.go:1263-1281: any read since the PING cancels the close"
354
+ },
355
+ call_deadline: {
356
+ duration: {
357
+ knob: "call_timeout",
358
+ unit: "s"
359
+ },
360
+ lateness: {
361
+ knob: "slack",
362
+ unit: "s"
363
+ },
364
+ arms: ["rx.headers"],
365
+ cancels: [
366
+ "local.stream-end",
367
+ "peer.rst",
368
+ "peer.fin",
369
+ "socket.error"
370
+ ],
371
+ fires: "timer.call-deadline",
372
+ note: "http2_server.go:603-615: from the read of the headers of the call. Its end resets the stream, and it does not end the connection"
373
+ },
374
+ max_idle: {
375
+ duration: {
376
+ knob: "max_connection_idle",
377
+ unit: "s"
378
+ },
379
+ lateness: {
380
+ knob: "slack",
381
+ unit: "s"
382
+ },
383
+ arms: ["enter:idle"],
384
+ cancels: ["rx.headers"],
385
+ fires: "timer.max-idle",
386
+ note: "http2_server.go:1222-1238: off at the defaults"
387
+ },
388
+ max_age: {
389
+ duration: {
390
+ knob: "max_connection_age",
391
+ unit: "s"
392
+ },
393
+ early: {
394
+ expr: "0.1 * max_connection_age",
395
+ unit: "s"
396
+ },
397
+ lateness: {
398
+ expr: "0.1 * max_connection_age + slack",
399
+ unit: "s"
400
+ },
401
+ arms: ["local.accept"],
402
+ fires: "timer.max-age",
403
+ note: "http2_server.go:231-232, :1239-1241: with a jitter of ±10 %. Off at the defaults"
404
+ },
405
+ grace: {
406
+ duration: {
407
+ knob: "max_connection_age_grace",
408
+ unit: "s"
409
+ },
410
+ lateness: {
411
+ knob: "slack",
412
+ unit: "s"
413
+ },
414
+ arms: ["timer.max-age"],
415
+ fires: "timer.grace",
416
+ note: "http2_server.go:1240-1251: the close after the GOAWAY of the age"
417
+ }
418
+ },
419
+ realizes: {
420
+ "systems.mechanism.heartbeat-interval": { timer: "keepalive" },
421
+ "systems.mechanism.heartbeat-detection-time": {
422
+ duration: {
423
+ expr: "keepalive_time + keepalive_timeout",
424
+ unit: "s"
425
+ },
426
+ lateness: {
427
+ expr: "2 * slack",
428
+ unit: "s"
429
+ },
430
+ note: "The PING after Time with no read, and the close Timeout after it"
431
+ },
432
+ "systems.mechanism.idle-refresh-interval": {
433
+ duration: {
434
+ knob: "listener_keepidle",
435
+ unit: "s"
436
+ },
437
+ lateness: {
438
+ model: "linux.wheel",
439
+ knobs: ["listener_keepidle", "hz"],
440
+ unit: "s"
441
+ },
442
+ early: {
443
+ model: "linux.jiffy",
444
+ knobs: ["hz"],
445
+ unit: "s"
446
+ },
447
+ note: "The first probe of the TCP keepalive of the accepted connection, rounded up on the wheel: no other segment goes out on an idle connection for 2 h"
448
+ }
449
+ },
450
+ transitions: [
451
+ {
452
+ id: "gs.accept",
453
+ from: "[none]",
454
+ to: "handshake",
455
+ on: "local.accept",
456
+ timer: "connection_timeout",
457
+ source: "server.go:1000-1009"
458
+ },
459
+ {
460
+ id: "gs.ready",
461
+ from: "handshake",
462
+ to: "idle",
463
+ on: "rx.settings",
464
+ source: "http2_server.go:205-300"
465
+ },
466
+ {
467
+ id: "gs.handshake-timeout",
468
+ from: "handshake",
469
+ to: "ended",
470
+ on: "timer.connection-timeout",
471
+ timer: "connection_timeout",
472
+ emits: ["tx.fin"],
473
+ source: "server.go:1005-1013"
474
+ },
475
+ {
476
+ id: "gs.stream",
477
+ from: "idle",
478
+ to: "active",
479
+ on: "rx.headers",
480
+ source: "http2_server.go"
481
+ },
482
+ {
483
+ id: "gs.stream-end",
484
+ from: "active",
485
+ to: "idle",
486
+ on: "local.stream-end",
487
+ source: "http2_server.go"
488
+ },
489
+ {
490
+ id: "gs.call-deadline",
491
+ from: "active",
492
+ to: "active",
493
+ on: "timer.call-deadline",
494
+ timer: "call_deadline",
495
+ emits: ["tx.rst-stream"],
496
+ note: "The stream of the call ends with RST_STREAM CANCEL. The connection stays, and another open stream goes on",
497
+ source: "http2_server.go:603-615"
498
+ },
499
+ {
500
+ id: "gs.ping-idle",
501
+ from: "idle",
502
+ to: "idle",
503
+ on: "timer.keepalive",
504
+ timer: "keepalive",
505
+ emits: ["tx.ping"],
506
+ source: "http2_server.go:1267-1274"
507
+ },
508
+ {
509
+ id: "gs.ping-active",
510
+ from: "active",
511
+ to: "active",
512
+ on: "timer.keepalive",
513
+ timer: "keepalive",
514
+ emits: ["tx.ping"],
515
+ source: "http2_server.go:1267-1274"
516
+ },
517
+ {
518
+ id: "gs.ping-timeout",
519
+ from: ["idle", "active"],
520
+ to: "ended",
521
+ on: "timer.ping-timeout",
522
+ timer: "ping_timeout",
523
+ errno: "keepalive ping not acked within timeout",
524
+ emits: ["tx.fin"],
525
+ source: "http2_server.go:1263-1266, :1291-1310"
526
+ },
527
+ {
528
+ id: "gs.too-many-pings",
529
+ from: ["idle", "active"],
530
+ to: "ended",
531
+ on: "rx.ping-strike-3",
532
+ errno: "too_many_pings",
533
+ emits: ["tx.goaway", "tx.fin"],
534
+ note: "GOAWAY ENHANCE_YOUR_CALM with the data too_many_pings, then the close of the connection",
535
+ source: "http2_server.go:929-932"
536
+ },
537
+ {
538
+ id: "gs.max-idle",
539
+ from: "idle",
540
+ to: "draining",
541
+ on: "timer.max-idle",
542
+ timer: "max_idle",
543
+ emits: ["tx.goaway"],
544
+ source: "http2_server.go:1232-1236"
545
+ },
546
+ {
547
+ id: "gs.max-age",
548
+ from: ["idle", "active"],
549
+ to: "draining",
550
+ on: "timer.max-age",
551
+ timer: "max_age",
552
+ emits: ["tx.goaway"],
553
+ source: "http2_server.go:1239-1241"
554
+ },
555
+ {
556
+ id: "gs.stop",
557
+ from: ["idle", "active"],
558
+ to: "draining",
559
+ on: "app.stop",
560
+ emits: ["tx.goaway"],
561
+ source: "server.go:1683"
562
+ },
563
+ {
564
+ id: "gs.drained",
565
+ from: "draining",
566
+ to: "ended",
567
+ on: ["timer.grace", "local.stream-end"],
568
+ emits: ["tx.fin"],
569
+ source: "http2_server.go:1242-1251"
570
+ },
571
+ {
572
+ id: "gs.reset",
573
+ from: [
574
+ "handshake",
575
+ "idle",
576
+ "active",
577
+ "draining"
578
+ ],
579
+ to: "ended",
580
+ on: ["socket.error", "peer.rst"],
581
+ errno: "ECONNRESET",
582
+ note: "The error of the socket, with its own code: ETIMEDOUT for an abort of the keepalive or a give-up of the kernel",
583
+ source: "http2_server.go"
584
+ },
585
+ {
586
+ id: "gs.closed",
587
+ from: [
588
+ "handshake",
589
+ "idle",
590
+ "active",
591
+ "draining"
592
+ ],
593
+ to: "ended",
594
+ on: "peer.fin",
595
+ errno: "EOF",
596
+ emits: ["tx.fin"],
597
+ source: "http2_server.go"
598
+ }
599
+ ],
600
+ over: {
601
+ machine: "systems.machine.linux-tcp",
602
+ states: {
603
+ handshake: "ESTABLISHED",
604
+ idle: "ESTABLISHED",
605
+ active: "ESTABLISHED",
606
+ draining: "ESTABLISHED"
607
+ },
608
+ sets: {
609
+ keepidle: {
610
+ expr: "ceil(listener_keepidle)",
611
+ unit: "s"
612
+ },
613
+ keepintvl: {
614
+ expr: "ceil(listener_keepintvl)",
615
+ unit: "s"
616
+ },
617
+ keepcnt: {
618
+ expr: "sets_user_timeout * max(1, ceil((keepalive_timeout - ceil(listener_keepidle)) / ceil(listener_keepintvl))) + (1 - sets_user_timeout) * listener_keepcnt",
619
+ unit: "count"
620
+ },
621
+ tcp_user_timeout: {
622
+ expr: "1000 * sets_user_timeout * keepalive_timeout",
623
+ unit: "ms"
624
+ }
625
+ },
626
+ ends: "socket.error",
627
+ note: "The accepted socket: a Linux TCP socket with the keepalive of Go. Where TCP_USER_TIMEOUT reaches it, the keepalive aborts at its first firing that is U after the last received segment, with a probe out: a keepalive of count k, k = max(1, ceil((U − K) / I)). U also ends a send with no ACK, U after its first retransmission"
628
+ }
629
+ });
630
+ /**
631
+ * This document is a server of grpc-go v1.84.0 on its own listener: grpc.NewServer on net.Listen, at the
632
+ * defaults, as in the server of the harness. Its keepalive is on (a PING after 2 h with no read). Thus the
633
+ * transport gives each accepted connection a TCP_USER_TIMEOUT of 20 s. With the TCP keepalive of Go
634
+ * (15 s, 15 s, 9), an idle connection to a client that is gone ends 30 s after the last data. A client
635
+ * that pings more often than 5 min with a stream open, or than 2 h with none, gets GOAWAY
636
+ * too_many_pings at its third strike.
637
+ */
638
+ const GRPC_GO_SERVER = serverOf({
639
+ id: "grpc-go-server",
640
+ title: "A server of grpc-go v1.84.0: one HTTP/2 connection, its keepalive, its policy for the PINGs of a client and its TCP socket",
641
+ version: "1.84.0",
642
+ conditions: {
643
+ "grpc-go": "v1.84.0",
644
+ go: "1.27.2",
645
+ server: "grpc.NewServer with the server options of the caller, on net.Listen",
646
+ transport: "HTTP/2 over TCP, with no TLS"
647
+ },
648
+ sources: [],
649
+ minTime: 300,
650
+ listenerIdle: 15,
651
+ setsUserTimeout: 1,
652
+ note: "dial.go:20: the default of Go, on net.Listen. A ListenConfig with its own KeepAlive changes it"
653
+ });
654
+ /**
655
+ * This document is the server of etcd v3.6.15, on grpc-go v1.83.2, at the defaults: one client URL with no
656
+ * TLS. The keepalive of the server is 2 h and 20 s, and a client can ping each 5 s with a stream open.
657
+ * The server serves gRPC and HTTP on one port through cmux. Thus the transport gets a wrapper of the conn,
658
+ * and it sets no TCP_USER_TIMEOUT. The listener sets the keepalive idle to 30 s. The interval and the
659
+ * count of Go stay. Thus an idle connection to a gone client ends 165 s after the last data: 30 + 9 × 15.
660
+ */
661
+ const ETCD_SERVER = serverOf({
662
+ id: "etcd-server",
663
+ title: "The server of etcd v3.6.15 on grpc-go v1.83.2: one gRPC connection of a client, its keepalive, its policy for PINGs and its TCP socket",
664
+ version: "3.6.15",
665
+ conditions: {
666
+ etcd: "v3.6.15",
667
+ "grpc-go": "v1.83.2",
668
+ go: "1.26.8",
669
+ server: "etcd with one member at its defaults, one client URL of http: and no TLS",
670
+ transport: "HTTP/2 over TCP through cmux, with no TLS"
671
+ },
672
+ sources: [
673
+ {
674
+ ref: `${ETCD} server/embed/config.go:69-71 --grpc-keepalive-min-time 5 s, --grpc-keepalive-interval 2 h, --grpc-keepalive-timeout 20 s`,
675
+ rung: "implemented"
676
+ },
677
+ {
678
+ ref: `${ETCD} server/embed/etcd.go:780-793 the policy (MinTime, PermitWithoutStream false) and the parameters (Time, Timeout) of the gRPC server`,
679
+ rung: "implemented"
680
+ },
681
+ {
682
+ ref: `${ETCD} server/embed/etcd.go:707-712 and client/pkg/transport/listener.go:48-116 a client URL with no socket options gets net.Listen in a keepalive listener`,
683
+ rung: "implemented"
684
+ },
685
+ {
686
+ ref: `${ETCD} client/pkg/transport/keepalive_listener.go:52-71 each accepted connection: SetKeepAlive(true) and SetKeepAlivePeriod(30 s), which sets the idle only (${GO}/tcpsock.go:249-257)`,
687
+ rung: "implemented"
688
+ },
689
+ {
690
+ ref: `${ETCD} server/embed/serve.go:141, :214-216 the gRPC server serves the HTTP/2 connections of cmux, a MuxConn (github.com/soheilhy/cmux v0.1.5 cmux.go:274-277), not a *net.TCPConn`,
691
+ rung: "implemented"
692
+ },
693
+ {
694
+ ref: `${ETCD} server/etcdserver/api/v3rpc/grpc.go:86-88 the server registers the health service of gRPC`,
695
+ rung: "implemented"
696
+ }
697
+ ],
698
+ minTime: 5,
699
+ listenerIdle: 30,
700
+ setsUserTimeout: 0,
701
+ note: "keepalive_listener.go:68: SetKeepAlivePeriod(30 s) on each accepted connection"
702
+ });
703
+ //#endregion
704
+ //#region src/grpc/grpc-js.ts
705
+ const AT$8 = "@grpc/grpc-js 1.14.6 src";
706
+ /**
707
+ * This document is grpc-js 1.14.6 on Node, for one channel to one server with no TLS, its transport
708
+ * (one HTTP/2 session on one TCP connection) and one unary call on it. It gives the states of the
709
+ * transport, from its connect to its end, and the timers that act on it.
710
+ *
711
+ * At the defaults the keepalive of grpc-js is off: it sends no PING. It sets TCP_NODELAY and no TCP
712
+ * keepalive, and its connect has no timeout. A call has no deadline. Thus nothing in grpc-js ends a
713
+ * call on a silent connection: only the kernel can, or the server.
714
+ *
715
+ * When the transport ends, each call in flight on it ends with UNAVAILABLE. The client does not retry such
716
+ * a call, because the call reached the server (PROCESSED). It retries only a call that did not start, and
717
+ * once a stream that the server refused. The channel then goes IDLE, and the next call connects again. A call
718
+ * that finds the channel in TRANSIENT_FAILURE fails at once, unless it asks to wait for the channel.
719
+ */
720
+ const GRPC_JS = machineSchema.parse({
721
+ format: "mark1russell7.machine/1",
722
+ id: "grpc-js",
723
+ title: "grpc-js 1.14.6: one channel to a gRPC server, its HTTP/2 transport, its keepalive and a unary call",
724
+ layer: "driver",
725
+ version: "1.14.6",
726
+ conditions: {
727
+ "grpc-js": "1.14.6",
728
+ node: "24.21.0",
729
+ client: "a Client of grpc-js with the channel options of the caller, and unary calls with no deadline and no waitForReady",
730
+ transport: "HTTP/2 over TCP to a host and port, with no TLS (createInsecure), and the load balancer pick_first",
731
+ server: "any gRPC server"
732
+ },
733
+ sources: [
734
+ {
735
+ ref: `${AT$8}/transport.ts:70 KEEPALIVE_TIMEOUT_MS is 20000`,
736
+ rung: "implemented"
737
+ },
738
+ {
739
+ ref: `${AT$8}/transport.ts:183-198 grpc.keepalive_time_ms is -1 when the caller gives none, grpc.keepalive_timeout_ms is 20000, and grpc.keepalive_permit_without_calls is false`,
740
+ rung: "implemented"
741
+ },
742
+ {
743
+ ref: `${AT$8}/transport.ts:447-453 a PING goes out only with a keepalive time above 0, and with a call in flight or permit_without_calls`,
744
+ rung: "implemented"
745
+ },
746
+ {
747
+ ref: `${AT$8}/transport.ts:455-507 each PING starts a timer of keepalive_timeout_ms, and its end with no ACK ends the transport (handleDisconnect). A failed send of the PING ends it too`,
748
+ rung: "implemented"
749
+ },
750
+ {
751
+ ref: `${AT$8}/transport.ts:515-534 and :553-561 the keepalive timer starts with the first call in flight, and after each ACK. It is not reset by data. When it ends with no call in flight, the PING goes out at the start of the next call`,
752
+ rung: "implemented"
753
+ },
754
+ {
755
+ ref: `${AT$8}/transport.ts:200-242 a close or an error of the session, or a close of its socket, ends the transport. A GOAWAY makes it unusable (reportDisconnectToOwner)`,
756
+ rung: "implemented"
757
+ },
758
+ {
759
+ ref: `${AT$8}/transport.ts:205-227 a GOAWAY ENHANCE_YOUR_CALM with the data too_many_pings tells the subchannel that the server refused the pings`,
760
+ rung: "implemented"
761
+ },
762
+ {
763
+ ref: `${AT$8}/transport.ts:431-441 handleDisconnect: each call in flight gets onDisconnect, and the session is destroyed in the next turn of the event loop`,
764
+ rung: "implemented"
765
+ },
766
+ {
767
+ ref: `${AT$8}/transport.ts:684-687 shutdown closes the session: a GOAWAY, then the end of the socket after the last stream`,
768
+ rung: "implemented"
769
+ },
770
+ {
771
+ ref: `${AT$8}/transport.ts:792-810 the transport is ready at the first SETTINGS of the server (remoteSettings)`,
772
+ rung: "implemented"
773
+ },
774
+ {
775
+ ref: `${AT$8}/transport.ts:818-840 the TCP connect is net.connect with no timeout`,
776
+ rung: "implemented"
777
+ },
778
+ {
779
+ ref: `${AT$8}/transport.ts:862 setNoDelay on each connection: TCP_NODELAY, thus no Nagle. No setKeepAlive anywhere in the package`,
780
+ rung: "implemented"
781
+ },
782
+ {
783
+ ref: `${AT$8}/subchannel-call.ts:360-371 onDisconnect ends the call with UNAVAILABLE 'Connection dropped' in the next turn of the event loop, unless the stream ends first`,
784
+ rung: "implemented"
785
+ },
786
+ {
787
+ ref: `${AT$8}/subchannel-call.ts:230-329 the end of a stream with no status: REFUSED_STREAM is UNAVAILABLE, CANCEL after a dropped connection is UNAVAILABLE, and an internal error of ECONNRESET or ETIMEDOUT is UNAVAILABLE`,
788
+ rung: "implemented"
789
+ },
790
+ {
791
+ ref: `${AT$8}/load-balancing-call.ts:257-261 a stream that the server refused has the progress REFUSED, and any other started stream PROCESSED`,
792
+ rung: "implemented"
793
+ },
794
+ {
795
+ ref: `${AT$8}/retrying-call.ts:631-652 a transparent retry for NOT_STARTED, and one for REFUSED. A PROCESSED call is retried only by a retry policy of the service config, which the defaults do not have`,
796
+ rung: "implemented"
797
+ },
798
+ {
799
+ ref: `${AT$8}/load-balancing-call.ts:338-345 a pick in TRANSIENT_FAILURE fails the call at once, unless it asks for waitForReady`,
800
+ rung: "implemented"
801
+ },
802
+ {
803
+ ref: `${AT$8}/resolving-call.ts:118-180 the deadline of a call is a timer from the start of the call. Its end cancels the call with DEADLINE_EXCEEDED`,
804
+ rung: "implemented"
805
+ },
806
+ {
807
+ ref: `${AT$8}/deadline.ts:39-52 the header grpc-timeout is the time left to the deadline when the call sends its headers, rounded up to whole milliseconds. A server can start a timer of it`,
808
+ rung: "implemented"
809
+ },
810
+ {
811
+ ref: `${AT$8}/subchannel-call.ts:269-279 a RST_STREAM CANCEL of the server ends the call with CANCELLED 'Call cancelled'`,
812
+ rung: "implemented"
813
+ },
814
+ {
815
+ ref: "run 39272272260 (T01.array.206): a deadline of 4 s against a server of grpc-go ended 4 of 11 calls with CANCELLED, each in the band of the deadline. In each of the 4, the handler at the server ended 1.1 ms before the end of the call. In 7 runs with DEADLINE_EXCEEDED it ended later, or at most 1.5 ms before",
816
+ rung: "observed"
817
+ },
818
+ {
819
+ ref: `${AT$8}/subchannel.ts:275-291 the end of the transport takes the subchannel from READY to IDLE. After too_many_pings the keepalive time doubles`,
820
+ rung: "implemented"
821
+ },
822
+ {
823
+ ref: `${AT$8}/subchannel.ts:298-304 a failed connect takes the subchannel to TRANSIENT_FAILURE`,
824
+ rung: "implemented"
825
+ },
826
+ {
827
+ ref: `${AT$8}/backoff-timeout.ts:23-26 the reconnect waits 1000 ms first, each next wait 1.6 times longer, up to 120000 ms, with a jitter of 0.2`,
828
+ rung: "implemented"
829
+ },
830
+ {
831
+ ref: `${AT$8}/internal-channel.ts:74-77 and :324-325 a channel with no call for grpc.client_idle_timeout_ms goes IDLE: 30 min at the defaults, 1 s at least`,
832
+ rung: "implemented"
833
+ },
834
+ {
835
+ ref: "node v24.21.0 lib/net.js:589 (a socket has no timeout until setTimeout), :828-843 (setNoDelay)",
836
+ rung: "implemented"
837
+ },
838
+ {
839
+ ref: "node v24.21.0 lib/internal/http2/core.js: no PING of its own, and no timeout of the session at the defaults",
840
+ rung: "implemented"
841
+ }
842
+ ],
843
+ states: {
844
+ "[none]": {
845
+ initial: true,
846
+ pseudo: true,
847
+ note: "Before the first call: the channel is IDLE"
848
+ },
849
+ connecting: { note: "The TCP connect, with TCP_NODELAY, no keepalive and no timeout (transport.ts:818-862). The call waits in the queue of the channel" },
850
+ opening: { note: "The HTTP/2 preface and the SETTINGS of the client, until the first SETTINGS of the server (transport.ts:792-810)" },
851
+ idle: { note: "A ready transport with no call in flight. At the defaults no timer runs on it" },
852
+ waiting: { note: "A unary call in flight: the call waits for its status, with no timer at the defaults" },
853
+ ended: {
854
+ final: true,
855
+ note: "The transport ended. Each call in flight ended with UNAVAILABLE, and the channel is IDLE until the next call"
856
+ }
857
+ },
858
+ events: {
859
+ "app.call": {
860
+ kind: "app",
861
+ note: "The application starts a unary call, for example grpc.health.v1.Health/Check"
862
+ },
863
+ "socket.connect": {
864
+ kind: "local",
865
+ note: "The TCP connect ends, and the session sends its preface and its SETTINGS"
866
+ },
867
+ "rx.settings": {
868
+ kind: "rx",
869
+ note: "The first SETTINGS of the server: the transport is ready, and the queued call goes out"
870
+ },
871
+ "rx.reply": {
872
+ kind: "rx",
873
+ note: "The status of the call, in the trailers of its stream"
874
+ },
875
+ "rx.ping-ack": {
876
+ kind: "rx",
877
+ note: "The ACK of a PING of the keepalive"
878
+ },
879
+ "rx.goaway": {
880
+ kind: "rx",
881
+ note: "A GOAWAY of the server. The transport takes no new call"
882
+ },
883
+ "peer.fin": {
884
+ kind: "peer",
885
+ note: "The server or a middlebox ends the connection: an end of the socket"
886
+ },
887
+ "peer.rst": {
888
+ kind: "peer",
889
+ note: "A reset of the connection: the socket fails with ECONNRESET"
890
+ },
891
+ "socket.error": {
892
+ kind: "local",
893
+ note: "The socket fails with its own error: a reset, or a give-up of the kernel (ETIMEDOUT, EHOSTUNREACH)"
894
+ },
895
+ "timer.keepalive": {
896
+ kind: "timer",
897
+ note: "The keepalive timer ends: the transport sends a PING"
898
+ },
899
+ "timer.ping-timeout": {
900
+ kind: "timer",
901
+ note: "No ACK came for the PING in keepalive_timeout_ms"
902
+ },
903
+ "timer.deadline": {
904
+ kind: "timer",
905
+ note: "The deadline of the call ends: DEADLINE_EXCEEDED"
906
+ },
907
+ "timer.idle": {
908
+ kind: "timer",
909
+ note: "The channel had no call for client_idle_timeout_ms"
910
+ },
911
+ "timer.reconnect": {
912
+ kind: "timer",
913
+ note: "The backoff of the subchannel ends: the next connect can start"
914
+ },
915
+ "tx.ping": {
916
+ kind: "tx",
917
+ note: "A PING frame of the keepalive"
918
+ },
919
+ "tx.goaway": {
920
+ kind: "tx",
921
+ note: "The GOAWAY of a session that the client closes (shutdown)"
922
+ },
923
+ "tx.fin": {
924
+ kind: "tx",
925
+ note: "The end of the socket of grpc-js, when the session is destroyed: its FIN"
926
+ }
927
+ },
928
+ knobs: {
929
+ keepalive_time: {
930
+ key: "grpc.keepalive_time_ms",
931
+ scope: "client",
932
+ unit: "ms",
933
+ default: 0,
934
+ off: 0,
935
+ note: "transport.ts:183-187, :447-453: -1 when the caller gives none, and the keepalive sends no PING unless the value is above 0. 0 here is that state: off"
936
+ },
937
+ keepalive_timeout: {
938
+ key: "grpc.keepalive_timeout_ms",
939
+ scope: "client",
940
+ unit: "ms",
941
+ default: 2e4,
942
+ note: "transport.ts:70, :188-192: the wait for the ACK of each PING"
943
+ },
944
+ keepalive_permit_without_calls: {
945
+ key: "grpc.keepalive_permit_without_calls",
946
+ scope: "client",
947
+ unit: null,
948
+ default: 0,
949
+ note: "transport.ts:193-198: 1 sends the PINGs with no call in flight too"
950
+ },
951
+ deadline: {
952
+ key: "the deadline of a call",
953
+ scope: "client",
954
+ unit: "ms",
955
+ default: 0,
956
+ off: 0,
957
+ note: "client.ts:72: no deadline unless the caller gives one"
958
+ },
959
+ initial_reconnect_backoff: {
960
+ key: "grpc.initial_reconnect_backoff_ms",
961
+ scope: "client",
962
+ unit: "ms",
963
+ default: 1e3,
964
+ note: "backoff-timeout.ts:23"
965
+ },
966
+ max_reconnect_backoff: {
967
+ key: "grpc.max_reconnect_backoff_ms",
968
+ scope: "client",
969
+ unit: "ms",
970
+ default: 12e4,
971
+ note: "backoff-timeout.ts:25"
972
+ },
973
+ client_idle_timeout: {
974
+ key: "grpc.client_idle_timeout_ms",
975
+ scope: "client",
976
+ unit: "ms",
977
+ default: 18e5,
978
+ note: "internal-channel.ts:77: 30 min"
979
+ },
980
+ slack: {
981
+ key: "the lateness of the event loop of Node for one step",
982
+ scope: "process",
983
+ unit: "s",
984
+ default: .01,
985
+ note: "An assumption of this document, not a value of grpc-js: a timer or a callback of Node that comes late"
986
+ },
987
+ hz: {
988
+ key: "CONFIG_HZ",
989
+ scope: "global",
990
+ unit: "Hz",
991
+ default: null,
992
+ note: "The build option of the kernel"
993
+ }
994
+ },
995
+ timers: {
996
+ keepalive: {
997
+ duration: {
998
+ knob: "keepalive_time",
999
+ unit: "ms"
1000
+ },
1001
+ lateness: {
1002
+ knob: "slack",
1003
+ unit: "s"
1004
+ },
1005
+ arms: ["enter:waiting", "rx.ping-ack"],
1006
+ fires: "timer.keepalive",
1007
+ note: "transport.ts:515-534, :553-561: from the first call in flight and from each ACK, not from data. Off at the defaults"
1008
+ },
1009
+ ping_timeout: {
1010
+ duration: {
1011
+ knob: "keepalive_timeout",
1012
+ unit: "ms"
1013
+ },
1014
+ lateness: {
1015
+ knob: "slack",
1016
+ unit: "s"
1017
+ },
1018
+ arms: ["tx.ping"],
1019
+ cancels: [
1020
+ "rx.ping-ack",
1021
+ "socket.error",
1022
+ "peer.rst",
1023
+ "peer.fin"
1024
+ ],
1025
+ fires: "timer.ping-timeout",
1026
+ note: "transport.ts:472-477: the end of the wait for the ACK ends the transport. Only a PING arms it, thus it does not run at the defaults"
1027
+ },
1028
+ deadline: {
1029
+ duration: {
1030
+ knob: "deadline",
1031
+ unit: "ms"
1032
+ },
1033
+ lateness: {
1034
+ knob: "slack",
1035
+ unit: "s"
1036
+ },
1037
+ arms: ["app.call", "enter:waiting"],
1038
+ cancels: [
1039
+ "rx.reply",
1040
+ "socket.error",
1041
+ "peer.rst",
1042
+ "peer.fin"
1043
+ ],
1044
+ fires: "timer.deadline",
1045
+ note: "resolving-call.ts:118-180: the deadline of the call, DEADLINE_EXCEEDED. No bound at the defaults. A server of grpc-go starts a timer of the same time from the header grpc-timeout, and its RST_STREAM CANCEL can reach the call first: then the call ends with CANCELLED"
1046
+ },
1047
+ idle_timeout: {
1048
+ duration: {
1049
+ knob: "client_idle_timeout",
1050
+ unit: "ms"
1051
+ },
1052
+ lateness: {
1053
+ knob: "slack",
1054
+ unit: "s"
1055
+ },
1056
+ arms: ["enter:idle"],
1057
+ cancels: ["app.call"],
1058
+ fires: "timer.idle",
1059
+ note: "internal-channel.ts:324-325, :655: the channel goes IDLE and closes its transport"
1060
+ },
1061
+ reconnect: {
1062
+ duration: {
1063
+ expr: "min(initial_reconnect_backoff * pow(1.6, fired), max_reconnect_backoff)",
1064
+ unit: "ms"
1065
+ },
1066
+ early: {
1067
+ expr: "0.2 * min(initial_reconnect_backoff * pow(1.6, fired), max_reconnect_backoff)",
1068
+ unit: "ms"
1069
+ },
1070
+ lateness: {
1071
+ expr: "0.2 * min(initial_reconnect_backoff * pow(1.6, fired), max_reconnect_backoff) + 1000 * slack",
1072
+ unit: "ms"
1073
+ },
1074
+ arms: ["enter:connecting"],
1075
+ cancels: ["rx.settings"],
1076
+ fires: "timer.reconnect",
1077
+ backoff: { resets: ["rx.settings"] },
1078
+ note: "backoff-timeout.ts:23-26, subchannel.ts:349-372: the backoff starts with each connect. A connect that fails before it ends waits for it. A ready transport stops it and starts it again from 1 s"
1079
+ }
1080
+ },
1081
+ realizes: {
1082
+ "systems.mechanism.heartbeat-interval": { timer: "keepalive" },
1083
+ "systems.mechanism.heartbeat-detection-time": {
1084
+ duration: {
1085
+ expr: "keepalive_time + keepalive_timeout",
1086
+ unit: "ms"
1087
+ },
1088
+ lateness: {
1089
+ expr: "2000 * slack",
1090
+ unit: "ms"
1091
+ },
1092
+ note: "With the keepalive on: the PING after keepalive_time, and the end of the transport keepalive_timeout after it. Off at the defaults"
1093
+ }
1094
+ },
1095
+ transitions: [
1096
+ {
1097
+ id: "gj.call",
1098
+ from: "[none]",
1099
+ to: "connecting",
1100
+ on: "app.call",
1101
+ note: "The first call takes the channel from IDLE to CONNECTING. The call waits in its queue",
1102
+ source: "internal-channel.ts, subchannel.ts:252-262"
1103
+ },
1104
+ {
1105
+ id: "gj.connected",
1106
+ from: "connecting",
1107
+ to: "opening",
1108
+ on: "socket.connect",
1109
+ note: "TCP_NODELAY, then the preface of HTTP/2",
1110
+ source: "transport.ts:842-870"
1111
+ },
1112
+ {
1113
+ id: "gj.ready",
1114
+ from: "opening",
1115
+ to: "waiting",
1116
+ on: "rx.settings",
1117
+ note: "The transport is ready, and the queued call goes out",
1118
+ source: "transport.ts:792-810, subchannel.ts:264-275"
1119
+ },
1120
+ {
1121
+ id: "gj.connect-failed",
1122
+ from: ["connecting", "opening"],
1123
+ to: "ended",
1124
+ on: [
1125
+ "socket.error",
1126
+ "peer.rst",
1127
+ "peer.fin"
1128
+ ],
1129
+ errno: "UNAVAILABLE",
1130
+ note: "The subchannel goes to TRANSIENT_FAILURE, and the queued call fails at once with UNAVAILABLE and the error of the connect (ECONNREFUSED for a reset of the SYN)",
1131
+ source: "subchannel.ts:298-304, load-balancing-call.ts:338-345"
1132
+ },
1133
+ {
1134
+ id: "gj.call-idle",
1135
+ from: "idle",
1136
+ to: "waiting",
1137
+ on: "app.call",
1138
+ source: "transport.ts:563-666"
1139
+ },
1140
+ {
1141
+ id: "gj.replied",
1142
+ from: "waiting",
1143
+ to: "idle",
1144
+ on: "rx.reply",
1145
+ source: "subchannel-call.ts:166-180"
1146
+ },
1147
+ {
1148
+ id: "gj.deadline",
1149
+ from: "waiting",
1150
+ to: "idle",
1151
+ on: "timer.deadline",
1152
+ timer: "deadline",
1153
+ errno: "DEADLINE_EXCEEDED",
1154
+ note: "The call ends, and the transport stays",
1155
+ source: "client.ts:72"
1156
+ },
1157
+ {
1158
+ id: "gj.ping",
1159
+ from: "waiting",
1160
+ to: "waiting",
1161
+ on: "timer.keepalive",
1162
+ timer: "keepalive",
1163
+ emits: ["tx.ping"],
1164
+ source: "transport.ts:455-507"
1165
+ },
1166
+ {
1167
+ id: "gj.ping-ack",
1168
+ from: "waiting",
1169
+ to: "waiting",
1170
+ on: "rx.ping-ack",
1171
+ source: "transport.ts:488-491"
1172
+ },
1173
+ {
1174
+ id: "gj.ping-timeout",
1175
+ from: ["idle", "waiting"],
1176
+ to: "ended",
1177
+ on: "timer.ping-timeout",
1178
+ timer: "ping_timeout",
1179
+ errno: "CLOSED",
1180
+ emits: ["tx.fin"],
1181
+ note: "The transport ends by itself and destroys its session. A call in flight ends with UNAVAILABLE 'Connection dropped'",
1182
+ source: "transport.ts:472-476, :431-441, subchannel-call.ts:360-371"
1183
+ },
1184
+ {
1185
+ id: "gj.reset",
1186
+ from: ["idle", "waiting"],
1187
+ to: "ended",
1188
+ on: ["socket.error", "peer.rst"],
1189
+ errno: "ECONNRESET",
1190
+ note: "The error of the socket, with its own code: ECONNRESET for a reset, ETIMEDOUT or EHOSTUNREACH for a give-up of the kernel. A call in flight ends with UNAVAILABLE",
1191
+ source: "transport.ts:230-242, :431-441, subchannel-call.ts:289-313"
1192
+ },
1193
+ {
1194
+ id: "gj.closed",
1195
+ from: ["idle", "waiting"],
1196
+ to: "ended",
1197
+ on: "peer.fin",
1198
+ errno: "EOF",
1199
+ emits: ["tx.fin"],
1200
+ note: "The end of the socket ends the session, and grpc-js destroys its side. A call in flight ends with UNAVAILABLE",
1201
+ source: "transport.ts:200-203, :237-242, :431-441"
1202
+ },
1203
+ {
1204
+ id: "gj.goaway",
1205
+ from: ["idle", "waiting"],
1206
+ to: "ended",
1207
+ on: "rx.goaway",
1208
+ errno: "GOAWAY",
1209
+ note: "The transport takes no new call, and the subchannel goes IDLE. A stream above the last stream id of the GOAWAY is refused and retried once. The server then ends the connection",
1210
+ source: "transport.ts:205-227, subchannel.ts:275-291"
1211
+ },
1212
+ {
1213
+ id: "gj.idle-timeout",
1214
+ from: "idle",
1215
+ to: "ended",
1216
+ on: "timer.idle",
1217
+ timer: "idle_timeout",
1218
+ emits: ["tx.goaway", "tx.fin"],
1219
+ source: "internal-channel.ts:655, transport.ts:684-687"
1220
+ }
1221
+ ],
1222
+ over: {
1223
+ machine: "systems.machine.linux-tcp",
1224
+ states: {
1225
+ connecting: "SYN_SENT",
1226
+ opening: "ESTABLISHED",
1227
+ idle: "ESTABLISHED",
1228
+ waiting: "ESTABLISHED"
1229
+ },
1230
+ sets: {},
1231
+ ends: "socket.error",
1232
+ note: "The socket of the transport: a Linux TCP socket with TCP_NODELAY and no keepalive. Thus the kernel ends a send with no ACK only at the give-up of its retransmissions, and an idle socket to a peer that is gone stays open"
1233
+ }
1234
+ });
1235
+ //#endregion
3
1236
  //#region src/http/timers.ts
4
1237
  /**
5
1238
  * This module gives the lateness of a timer in user space on Linux 6.6. A Node timer and a Go timer
@@ -13103,9 +14336,12 @@ const MACHINES = byId([
13103
14336
  AMQPLIB,
13104
14337
  RABBITMQ_CONNECTION,
13105
14338
  ATEN_DETECTOR,
13106
- RA_MEMBER
14339
+ RA_MEMBER,
14340
+ GRPC_JS,
14341
+ GRPC_GO_SERVER,
14342
+ ETCD_SERVER
13107
14343
  ]);
13108
14344
  //#endregion
13109
- export { AMQPLIB, ATEN_DETECTOR, GO_TRANSPORT, HIKARICP_PGJDBC, IOREDIS_SENTINEL, IOREDIS_STATUS, LINUX_TCP, MACHINES, MANIFESTATIONS, MONGODB_NODE, MONGOD_REPL, MONGOD_SESSION, NF_CONNTRACK_TCP, NODE_HTTP_AGENT, NODE_HTTP_SERVER, NODE_POSTGRES, NODE_TIMER_EARLY, PGBOUNCER_CLIENT, PGBOUNCER_SERVER, PGPOOL_SESSION, POSTGRES_SESSION, PROCEDURES_WS_CLIENT, PROCEDURES_WS_SERVER, RABBITMQ_CONNECTION, RA_MEMBER, REDIS_CLIENT, SENTINEL, SUPAVISOR_CLIENT, SUPAVISOR_SERVER, UNDICI_CLIENT, UNDICI_TICK_MS, goLateSeconds, goTimerLateness, nodeEarlySeconds, nodeLateSeconds, nodeTimerLateness, undiciFastEarly, undiciFastLateness };
14345
+ export { AMQPLIB, ATEN_DETECTOR, ETCD_SERVER, GO_TRANSPORT, GRPC_GO_SERVER, GRPC_JS, HIKARICP_PGJDBC, IOREDIS_SENTINEL, IOREDIS_STATUS, LINUX_TCP, MACHINES, MANIFESTATIONS, MONGODB_NODE, MONGOD_REPL, MONGOD_SESSION, NF_CONNTRACK_TCP, NODE_HTTP_AGENT, NODE_HTTP_SERVER, NODE_POSTGRES, NODE_TIMER_EARLY, PGBOUNCER_CLIENT, PGBOUNCER_SERVER, PGPOOL_SESSION, POSTGRES_SESSION, PROCEDURES_WS_CLIENT, PROCEDURES_WS_SERVER, RABBITMQ_CONNECTION, RA_MEMBER, REDIS_CLIENT, SENTINEL, SUPAVISOR_CLIENT, SUPAVISOR_SERVER, UNDICI_CLIENT, UNDICI_TICK_MS, goLateSeconds, goTimerLateness, nodeEarlySeconds, nodeLateSeconds, nodeTimerLateness, undiciFastEarly, undiciFastLateness };
13110
14346
 
13111
14347
  //# sourceMappingURL=index.js.map