-
Notifications
You must be signed in to change notification settings - Fork 11
waved: answer inbound RPCs to the envelope sender #1110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
2ac35c0
fa52ed8
a1e504f
6abaafe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3567,6 +3567,16 @@ func (s *Server) handleInboundRPC(ctx context.Context, | |
| return fmt.Errorf("missing envelope body") | ||
| } | ||
|
|
||
| // The sender is where the answer goes, so an absent one is the same | ||
| // lost-response failure an absent ReplyTo used to cause: the recipient | ||
| // would be empty and the mailbox store rejects that outright. Nothing | ||
| // upstream asserts it — the ingress version check only compares the | ||
| // two version fields — so refuse here, where the value is used, and | ||
| // let the ingress loop log the dispatch error. | ||
| if env.Sender == "" { | ||
| return fmt.Errorf("missing envelope sender") | ||
| } | ||
|
|
||
| // Dispatch through the mux to the registered handler. | ||
| respMsg, err := s.mailboxMux.ServeRPC( | ||
| ctx, env.Rpc.Service, env.Rpc.Method, env.Body.Value, | ||
|
|
@@ -3605,8 +3615,27 @@ func (s *Server) handleInboundRPC(ctx context.Context, | |
| } | ||
|
|
||
| responseEnv := &mailboxpb.Envelope{ | ||
| Sender: s.localMailboxID, | ||
| Recipient: env.Rpc.ReplyTo, | ||
| Sender: s.localMailboxID, | ||
|
|
||
| // A response belongs to whoever sent the request, so address | ||
| // it to the sender rather than to the request's ReplyTo. | ||
| // | ||
| // The two agree for every producer in this repo: each sets | ||
| // Sender and Rpc.ReplyTo to the same LocalMailboxID (see | ||
| // serverconn/unary_facade.go, serverconn/actor.go, | ||
| // serverconn/heartbeat.go and the operator's clientconn | ||
| // equivalents). So this changes nothing for a well-formed | ||
| // peer, and it stops a request choosing a destination that | ||
| // disagrees with where it came from. | ||
| // | ||
| // It also fixes an absent ReplyTo. That used to produce an | ||
| // empty recipient, which the mailbox store rejects outright, | ||
| // so the caller lost its answer entirely. | ||
| // | ||
| // Rpc.ReplyTo is therefore advisory from the responder's | ||
| // point of view: producers still set it, and nothing here | ||
| // reads it. | ||
| Recipient: env.Sender, | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 minor — The preamble checks its two siblings: if env.Rpc == nil { ... }
if env.Body == nil { ... }and So an inbound A third guard alongside the existing two closes it, and turns a silent drop into a dispatch error the ingress loop logs: if env.Sender == "" {
return fmt.Errorf("missing envelope sender")
}Worth a fourth table entry in |
||
| Headers: headers, | ||
| Body: body, | ||
| Rpc: &mailboxpb.RpcMeta{ | ||
|
|
@@ -3622,11 +3651,18 @@ func (s *Server) handleInboundRPC(ctx context.Context, | |
| // client's negotiated mailbox transport and Ark protocol versions. | ||
| s.runtime.StampEnvelope(responseEnv) | ||
|
|
||
| _, err = edge.Send(ctx, &mailboxpb.SendRequest{ | ||
| // Fold the response status in alongside the transport error: a mailbox | ||
| // rejection (an unknown recipient, a version mismatch) travels as | ||
| // Status.Ok=false, not as an error, so discarding it would report a | ||
| // dropped answer as a successful dispatch and leave the caller waiting | ||
| // on its correlation ID until it times out. | ||
| resp, err := edge.Send(ctx, &mailboxpb.SendRequest{ | ||
| Envelope: responseEnv, | ||
| }) | ||
| if err != nil { | ||
| return fmt.Errorf("send RPC response: %w", err) | ||
| if sErr := serverconn.SendResponseError( | ||
| "send rpc response", resp, err, | ||
| ); sErr != nil { | ||
| return sErr | ||
| } | ||
|
|
||
| return nil | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟠 major — This comment claims more than the change delivers. Removing the empty-
ReplyTocause is right, but the silence is what made that bug expensive, and the silence is still here.SendResponse.Statusis this codebase's canonical application-level failure channel —mailboxconn.StatusError,StatusMailboxVersionUnsupported,StatusArkVersionMismatch,StatusUpgradeRequiredall travel that way, never as a transporterror. Three of the fourEdge.Sendcall sites in the repo fold it correctly throughedgeResponseError(serverconn/unary_facade.go:143,serverconn/actor.go:1109,serverconn/heartbeat.go:117). This one, at line 3644, is the only one that discards it:So any rejection that arrives as
Status.Ok=false— a version mismatch, an unknown recipient, whatever the operator adds next — returnsnilhere.handleInboundRPCreports success, the ingress loop acks the request as dispatched, and the operator's waiter blocks until it times out. Nothing is logged on either side. That is the same failure mode the empty-ReplyTobug had; this PR removed one cause of it and left the detector missing, so the next cause will be just as invisible.This also makes the claim on these lines unfalsifiable from inside waved: whether the store really "rejects outright" is exactly what this send path cannot see. (The new test's
recordingReplyEdgeaccepts everything, so it does not establish the rejection either.)Suggest folding this send into the same helper as its three siblings:
(
edgeResponseErroris unexported inserverconn, so this needs a small exported wrapper — worth it to stopwavedbeing the one send path that cannot see a rejection.)To be clear: this is pre-existing and not introduced here, and I am not blocking on it. But the comment at these lines asserts the lost-answer problem is fixed, and with the status still dropped it is only narrowed.