Skip to content

Report handler panics as panics, not client disconnects - #1677

Draft
nshalman wants to merge 2 commits into
oxidecomputer:mainfrom
nshalman:panic-isnt-disconnect
Draft

Report handler panics as panics, not client disconnects#1677
nshalman wants to merge 2 commits into
oxidecomputer:mainfrom
nshalman:panic-isnt-disconnect

Conversation

@nshalman

@nshalman nshalman commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Supersedes #1359

We can keep or drop the tests at your discretion.

@nshalman
nshalman force-pushed the panic-isnt-disconnect branch from da88253 to 43b9b56 Compare August 7, 2026 01:36
Comment thread dropshot/src/server.rs Outdated
error!(request_log, "request handling panicked";
"latency_us" => latency_us,
);
return;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think we'd still want to fire a DTrace probe for this case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

When I finally get the test condition ironed out I will make sure to add that.
My follow up code that makes the instrumentation more abstract will have a clear spot for that to happen (the current draft I think doesn't fire the dtrace probe, but that is easily fixed.)

Comment thread dropshot/src/server.rs Outdated
let on_disconnect = guard((), |_| {
let latency_us = start_time.elapsed().as_micros();

if std::thread::panicking() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I don't think this condition is right. The thread currently panicking doesn't mean the handler panicked. One concrete example: suppose somebody else (outside of Dropshot) has a test that creates a Dropshot server, then does some work, the test fails (panics), resulting in everything being dropped. We'll wind up here because the thread is panicking, but it's not that the handler panicked.

(I've almost always found std::thread::panicking() to be the wrong check.)

I think the way to tell if the handler panicked is:

  • for the CancelOnDisconnect case: we'd have to catch_unwind
  • for the Detached case: check the result of awaiting on the tokio handle. I see we already do that and log a message about it below.

which makes me wonder how you ran into this? Are you in the CancelOnDisconnect case or does the Detached case not work right despite checking for that?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Update: clicked through to #1359 and see that it's the Detached case you're seeing. If I'm understanding right, you should be getting an error log message saying the handler panicked, then we propagate the panic and then you get a message and DTrace probe about it being a 499?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I will beef up the test cases and make sure I have all the reproducers as clear as possible at which point I should be able to figure out what the right check(s) should be. Thank you for your feedback!!

@nshalman
nshalman marked this pull request as draft August 7, 2026 17:44
@nshalman

nshalman commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

a19b6f9 adds a more thorough set of test cases and confirms your analysis that std::thread::panicking() was indeed the wrong check.

48f7c1a makes the tests pass. I need to reread it a few more times to wrap my head around it and trim down the comments to a more appropriate quantity. I might be able to make the code a little more readable to my own eye as well.

The main question that this surfaces is what kind of dtrace probe you would want to fire. Reuse request_done (as sketched out in 7609e8f) or create something else for it...

I also imagine that for your programs in release builds where

[profile.release]
panic = 'abort'

that the abort would prevent the dtrace probe from actually firing? Is my mental model accurate on that?

nshalman and others added 2 commits August 7, 2026 17:00
A handler panic, a panic elsewhere in request handling (a version
policy), a mid-handler client disconnect, and server teardown caused
by a panic elsewhere in the process -- in both handler task modes
where the mode matters.  Also a dtrace(8)-verified test of the USDT
probe payloads, runnable where dtrace and the privileges to use it
exist (DROPSHOT_DTRACE_TEST=require turns its skip into a failure).

The panic tests fail until the next commit: a panic escaping request
handling is currently misreported as a client disconnection, in the
log and in the request-done probe.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Poll http_request_handle inside catch_unwind: a caught panic defuses
the disconnect scopeguard, is logged with the panic message, fires the
request-done probe with status code 0 ("no response"), and propagates
as before.  The scopeguard now runs only on cancellation, however
caused.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@nshalman
nshalman force-pushed the panic-isnt-disconnect branch from 7609e8f to 58acfb7 Compare August 7, 2026 21:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants