Skip to content

Exit STM workers quietly on lost master connection (flaky output/Partac.v on Windows CI) - #22286

Open
JasonGross wants to merge 1 commit into
rocq-prover:masterfrom
JasonGross:quiet-worker-connection-loss
Open

Exit STM workers quietly on lost master connection (flaky output/Partac.v on Windows CI)#22286
JasonGross wants to merge 1 commit into
rocq-prover:masterfrom
JasonGross:quiet-worker-connection-loss

Conversation

@JasonGross

Copy link
Copy Markdown
Member

Written by Claude (Anthropic AI) at the request of and under the supervision of @JasonGross.

Problem

STM workers whose master goes away do not always see End_of_file. On Windows, the master closing the socket is observed by the worker's blocking read as WSAECONNRESET ("An existing connection was forcibly closed by the remote host.") or WSAECONNABORTED; on Unix, a write (e.g. of feedback) to a dead master fails with EPIPE ("Broken pipe"). All of these surface as Sys_error — possibly wrapped in MarshalError by the (un)marshalling helpers — and take the loud Slave: critical exception: / Fatal marshal error: branches of the worker main loop instead of the quiet connection lost one.

The loud message races into the master's output. Concretely, this makes output/Partac.v fail intermittently on Windows CI (seen on this run for #22266, whose diff is unrelated Ltac2 stdlib additions):

+260:tactic:1:1:0] Slave: critical exception: System error:
+                                             "An existing connection was forcibly closed by the remote host.
+"
 File "./output/Partac.v", line 4, characters 2-24:
 The command has indeed failed with message:
 ...

Fix

Recognize the connection-loss Sys_error texts (ECONNRESET/EPIPE/WSAECONNRESET/WSAECONNABORTED) in the worker main loop, in both the raw Sys_error position and the MarshalError-wrapped position, and exit through the same quiet path as End_of_file (the message is still printed with -debug misc, like connection lost today). Real worker crashes keep the loud reporting.

The strings are matched on the strerror text since the exceptions come out of in_channel/out_channel operations as Sys_error rather than Unix.Unix_error.

🤖 Generated with Claude Code

https://claude.ai/code/session_019ttctspSoVoquHLQtbPVZw

When the master tears down a worker's channels, the worker does not
always observe End_of_file: on Windows the socket read fails with
WSAECONNRESET ("An existing connection was forcibly closed by the
remote host") or WSAECONNABORTED, and on Unix a write to the dead
master fails with EPIPE ("Broken pipe"), all surfacing as Sys_error
(possibly wrapped in MarshalError). These took the loud "Slave:
critical exception" / "Fatal marshal error" branches of the worker
main loop instead of the quiet "connection lost" one, and the message
races into the master's output, e.g. making output/Partac.v fail
intermittently on Windows CI:

    260:tactic:1:1:0] Slave: critical exception: System error:
    "An existing connection was forcibly closed by the remote host."

Treat connection-loss Sys_errors like End_of_file.

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019ttctspSoVoquHLQtbPVZw
@coqbot-app coqbot-app Bot added the needs: full CI The latest GitLab pipeline that ran was a light CI. Say "@coqbot run full ci" to get a full CI. label Jul 16, 2026
@JasonGross
JasonGross marked this pull request as ready for review July 20, 2026 23:59
@JasonGross
JasonGross requested a review from a team as a code owner July 20, 2026 23:59
Comment thread stm/asyncTaskQueue.ml
stm_pr_err Pp.(prlist str ["Fatal marshal error: "; s]); flush_all (); exit 2
| End_of_file ->
stm_prerr_endline "connection lost"; flush_all (); exit 2
| Sys_error s when connection_lost s ->

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grepping the error message is below my standards, also because these things are translated using LOCALE.

Just catch any Sys_error.

Comment thread stm/asyncTaskQueue.ml
CEphemeron.clean ()
with
| MarshalError s when connection_lost s ->
stm_prerr_endline "connection lost"; flush_all (); exit 2

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here as well, I don't see the advantage of printing "connection lost" over "marshal error" and returning the same error code. please remove this hunk.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the alternative is adapting the test-suite runner to filter out these sorts of messages so that the test involving par is less flaky on Windows? Or adding support for expect tests with multiple alternatives and adding all the various alternatives we might see? I'll have Fable prepare two alternate PRs for each of these strategies, we can see which one is better

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand how printing "connection lost" is less flaky than printing "marshall error whatever"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please avoid spamming PRs, you can just link to your branch instead

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand how printing "connection lost" is less flaky than printing "marshall error whatever"

My understanding of the flakiness is that the behavior of the test is always the same, but the error message varies depending on thread interleaving. (Does this seem correct?)

Please avoid spamming PRs, you can just link to your branch instead

Apologies, and noted for the future.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding is that sometimes we get the message and sometimes we don't

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, if there is a test depending on the string, we can change it depending on the error code. That is fine to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs: full CI The latest GitLab pipeline that ran was a light CI. Say "@coqbot run full ci" to get a full CI.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants