Commit 42cc21a
committed
[kyo-net] Closed exceptions that name the failing connection, not the driver
## Problem
A user reported that Kyo's shared HTTP client wedges under load ([full report](https://gist.github.com/baldram/5c21566eacb4a5a361b6a60ead5af76d)). Under sustained concurrent traffic with connection churn (16 threads each running 200 requests against a server that restarted every 25ms, on the NIO backend), requests started failing with `NioIoDriver[sel=...] ... is closed. finishConnect failed`. The IO driver is a process-wide singleton shared by every `HttpClient`, every failure in the run named the same selector, and the failures did not stop, so the report concluded the shared driver had gone permanently closed for the life of the process, one failure taking down every later call.
That conclusion was wrong, and the error message is why. What happened during the churn is ordinary: an individual `finishConnect` lost its race against a server that had just restarted, and that one connection failed. But the failure was reported as `Closed` naming the driver, at a frame pointing into driver internals, so a routine per-connection failure read as the whole shared driver dying. The message turned a single connection failing into an apparent process-wide outage.
## Solution
`Closed` now names the resource that actually closed and carries that resource's own creation frame: a `connection` at the site it was opened, a `listener` at the site it began listening. A driver-internal frame remains only for a genuine whole-driver shutdown, the one case where the driver is the resource.
Failures that are not closures stop pretending to be. An OS-level read, connect, or accept error is now a typed `NetException` carrying the errno, which the transport still wraps into the public `NetConnectException` the caller already handles. Carrying the typed connect and accept errors meant widening an internal promise's error row from `Closed` to `Closed | NetException`, threaded through the real promise storage with no cast that narrows it back. The public exception types are unchanged.
The change adds two cross-backend resilience suites that did not exist before, `TransportResilienceTest` and `HttpServerResilienceTest`. They drive NIO, the kqueue and epoll poller, and io_uring through the failure modes the report implicated: connection churn, in-flight cancellation, RST and FIN and half-close, and connection-pool integrity, each time asserting that a co-tenant connection on the same shared driver keeps working while another one fails. They were the reproduction that showed the driver never wedges, and they stay as the guard that a per-connection failure can never again read as a driver-wide outage.
## Notes
- The reported permanent wedge does not exist. The resilience suites reproduce the report's load and never produce one: the driver stays live and keeps serving connections under the churn. The only defect the report actually surfaced is the misleading message, and that is what the repro validated.
- A separate io_uring bug, unrelated to the report, is fixed here too. A single transient accept error (`EINTR`, `ECONNABORTED`, or momentary file-descriptor exhaustion) made the driver fail the accept promise, and the accept loop reads any accept failure as the listener closing, so one transient errno permanently wedged the listener. It now re-arms the accept instead of failing it.
- That re-arm is deferred by a backoff for the two file-descriptor-exhaustion errnos. On `EMFILE`/`ENFILE` the kernel leaves the pending connection in the backlog, so re-arming immediately re-reaps the same errno at once and spins the reap carrier at full CPU. Those re-arm after a backoff instead, matching the poller, tunable through the new `-Dkyo.net.acceptResourceBackoff` flag (milliseconds, default 50), and guarded by a reproduction on a real io_uring ring.
- Validated on a real io_uring ring in a Linux container, including the end-of-run file-descriptor leak check, plus the NIO, poller, and JS drivers on the host, across JVM, JS, and Native.1 parent cda8136 commit 42cc21a
143 files changed
Lines changed: 2195 additions & 1074 deletions
File tree
- kyo-http/jvm/src/test/scala/kyo
- kyo-net
- js-wasm/src
- main/scala/kyo/net/internal
- test/scala/kyo/net/internal
- js/src/test/scala/kyo/net
- internal
- jvm-native/src/test/scala/kyo/net
- internal
- posix
- transport
- jvm/src
- main/scala/kyo/net/internal
- test/scala/kyo/net/internal
- transport
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2134 | 2134 | | |
2135 | 2135 | | |
2136 | 2136 | | |
2137 | | - | |
| 2137 | + | |
2138 | 2138 | | |
2139 | 2139 | | |
2140 | 2140 | | |
| |||
Lines changed: 324 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 15 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
| 4 | + | |
4 | 5 | | |
5 | 6 | | |
6 | 7 | | |
| |||
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
16 | | - | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| |||
55 | 56 | | |
56 | 57 | | |
57 | 58 | | |
58 | | - | |
| 59 | + | |
59 | 60 | | |
60 | | - | |
| 61 | + | |
61 | 62 | | |
62 | 63 | | |
63 | 64 | | |
| |||
91 | 92 | | |
92 | 93 | | |
93 | 94 | | |
94 | | - | |
| 95 | + | |
95 | 96 | | |
96 | 97 | | |
97 | 98 | | |
98 | | - | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
99 | 109 | | |
100 | 110 | | |
101 | 111 | | |
| |||
Lines changed: 10 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
| 4 | + | |
| 5 | + | |
4 | 6 | | |
5 | 7 | | |
6 | 8 | | |
| |||
64 | 66 | | |
65 | 67 | | |
66 | 68 | | |
67 | | - | |
| 69 | + | |
68 | 70 | | |
69 | 71 | | |
70 | 72 | | |
| |||
89 | 91 | | |
90 | 92 | | |
91 | 93 | | |
92 | | - | |
| 94 | + | |
93 | 95 | | |
94 | 96 | | |
95 | 97 | | |
96 | | - | |
| 98 | + | |
97 | 99 | | |
98 | | - | |
| 100 | + | |
99 | 101 | | |
100 | | - | |
| 102 | + | |
101 | 103 | | |
102 | 104 | | |
103 | 105 | | |
104 | 106 | | |
105 | | - | |
| 107 | + | |
106 | 108 | | |
107 | 109 | | |
108 | 110 | | |
| |||
125 | 127 | | |
126 | 128 | | |
127 | 129 | | |
128 | | - | |
| 130 | + | |
129 | 131 | | |
130 | 132 | | |
131 | 133 | | |
| |||
156 | 158 | | |
157 | 159 | | |
158 | 160 | | |
159 | | - | |
| 161 | + | |
160 | 162 | | |
161 | 163 | | |
162 | 164 | | |
| |||
Lines changed: 23 additions & 26 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
375 | 375 | | |
376 | 376 | | |
377 | 377 | | |
378 | | - | |
| 378 | + | |
379 | 379 | | |
380 | 380 | | |
381 | 381 | | |
| |||
394 | 394 | | |
395 | 395 | | |
396 | 396 | | |
397 | | - | |
| 397 | + | |
398 | 398 | | |
399 | 399 | | |
400 | 400 | | |
| |||
412 | 412 | | |
413 | 413 | | |
414 | 414 | | |
415 | | - | |
416 | | - | |
| 415 | + | |
| 416 | + | |
417 | 417 | | |
418 | 418 | | |
419 | 419 | | |
| |||
453 | 453 | | |
454 | 454 | | |
455 | 455 | | |
456 | | - | |
457 | | - | |
458 | | - | |
459 | | - | |
460 | | - | |
| 456 | + | |
461 | 457 | | |
462 | 458 | | |
463 | 459 | | |
| |||
471 | 467 | | |
472 | 468 | | |
473 | 469 | | |
474 | | - | |
| 470 | + | |
475 | 471 | | |
476 | 472 | | |
477 | 473 | | |
| |||
550 | 546 | | |
551 | 547 | | |
552 | 548 | | |
553 | | - | |
| 549 | + | |
554 | 550 | | |
555 | 551 | | |
556 | 552 | | |
| |||
559 | 555 | | |
560 | 556 | | |
561 | 557 | | |
562 | | - | |
| 558 | + | |
563 | 559 | | |
564 | 560 | | |
565 | 561 | | |
| |||
570 | 566 | | |
571 | 567 | | |
572 | 568 | | |
573 | | - | |
| 569 | + | |
574 | 570 | | |
575 | 571 | | |
576 | 572 | | |
| |||
630 | 626 | | |
631 | 627 | | |
632 | 628 | | |
633 | | - | |
634 | | - | |
| 629 | + | |
| 630 | + | |
635 | 631 | | |
636 | 632 | | |
637 | 633 | | |
| |||
661 | 657 | | |
662 | 658 | | |
663 | 659 | | |
664 | | - | |
| 660 | + | |
665 | 661 | | |
666 | 662 | | |
667 | 663 | | |
| |||
695 | 691 | | |
696 | 692 | | |
697 | 693 | | |
698 | | - | |
699 | | - | |
| 694 | + | |
| 695 | + | |
700 | 696 | | |
701 | 697 | | |
702 | 698 | | |
| |||
707 | 703 | | |
708 | 704 | | |
709 | 705 | | |
710 | | - | |
| 706 | + | |
711 | 707 | | |
712 | 708 | | |
713 | 709 | | |
| |||
771 | 767 | | |
772 | 768 | | |
773 | 769 | | |
774 | | - | |
| 770 | + | |
775 | 771 | | |
776 | 772 | | |
777 | 773 | | |
| |||
783 | 779 | | |
784 | 780 | | |
785 | 781 | | |
786 | | - | |
| 782 | + | |
787 | 783 | | |
788 | 784 | | |
789 | 785 | | |
| |||
792 | 788 | | |
793 | 789 | | |
794 | 790 | | |
795 | | - | |
| 791 | + | |
796 | 792 | | |
797 | 793 | | |
798 | 794 | | |
| |||
846 | 842 | | |
847 | 843 | | |
848 | 844 | | |
849 | | - | |
| 845 | + | |
850 | 846 | | |
851 | 847 | | |
852 | 848 | | |
| |||
1067 | 1063 | | |
1068 | 1064 | | |
1069 | 1065 | | |
1070 | | - | |
| 1066 | + | |
1071 | 1067 | | |
1072 | 1068 | | |
1073 | 1069 | | |
| |||
1077 | 1073 | | |
1078 | 1074 | | |
1079 | 1075 | | |
1080 | | - | |
| 1076 | + | |
1081 | 1077 | | |
1082 | 1078 | | |
1083 | 1079 | | |
| |||
1147 | 1143 | | |
1148 | 1144 | | |
1149 | 1145 | | |
1150 | | - | |
| 1146 | + | |
| 1147 | + | |
1151 | 1148 | | |
1152 | 1149 | | |
1153 | 1150 | | |
| |||
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
57 | 57 | | |
58 | 58 | | |
59 | 59 | | |
60 | | - | |
| 60 | + | |
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
| |||
77 | 77 | | |
78 | 78 | | |
79 | 79 | | |
80 | | - | |
| 80 | + | |
81 | 81 | | |
82 | 82 | | |
83 | 83 | | |
| |||
0 commit comments