WebSocket-dispatched Remote invocations carry no request context #5791
yuzisama224
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
The WebSocket upgrade is authenticated but carries nothing about the request forward, so every streamed Remote invocation is dispatched with no request in scope — even where the unary
/apipath has one.Where the request is lost
The upgrade route checks trust and then hands the socket to the mux (
packages/api/gateway/src/index.ts:205-229):reqis an ordinary HTTP request that has passed through whatever sits in front of the process. It is used for the trust check and then dropped. Everything that streams —session/follow,session/control,workspace/follow— is dispatched from frames on that socket, and none of it can see it.This is the same gap as the companion post about
client-connection(#5790), one transport over. That one covers unary/apicalls; this one covers everything that streams, and the two together are what an endpoint owner actually needs, because a session renders over the stream and is cancelled over/api.All references are to
dsh-v0.1.2-rc.1(a66e470).The part that is not obvious
Entering a scope around
handleUpgrade, or around the accept callback, does not work. We measured it: the request is readable inside the accept callback andundefinedin everymessagelistener, becausewsdelivers socket events on the socket's own async context rather than the upgrade's. By the time the first frame arrives the scope has unwound.Scoping only the mux's
openclosure is not enough either. That coversprepareInvocation, and therefore the lookup resolvers, but a Remote method declared as a generator has not run its body whenopenreturns, so anything the method itself reads falls outside.The scope has to be re-entered per socket event. The smallest place that does that is the accepted socket's own
emit, wrapped once where the per-socket connection is built (packages/api/gateway/src/stream-server.ts:48-57) — the first point at which anything is per-socket at all.The change we would propose
RemoteStreamMuxServertakes one more constructor argument, and it is optional:handleUpgradewraps the accepted socket'semitwith it only when one was supplied; a three-argument caller gets a socket whoseemitis the onewsgave it, which is exactly today's behaviour.index.tssupplies(req, dispatch) => webCtx.connection.runWithRequest(req, dispatch).Nothing new is injected for that:
connectionis already injected on that exact context (packages/api/gateway/src/index.ts:205). What the change does need is thatrunWithRequestbe declared onHostConnectionHandle, the interface that typesctx.connection— the companion change declares it there. This is why this change does not compile on its own even though it touches only gateway files. There is no second storage, and one request context serves both transports.The diff is two files and about 25 lines. It is attached or linked below.
Wrapping
emitis the blunt part of it, and we would rather be told a better one.wsgives no per-socket async context and no dispatch hook, so the alternatives we found were worse: patchingon/onceper event name misses listeners registered later, and moving the scope intoRemoteStreamMuxConnectionwould have to re-enter it at each of several read sites instead of one.What we are asking
emitacceptable, or is there a hook we missed?We run this as a local patch over the published
0.1.2-rc.1package today, verified two ways: interleaved frames from two live sockets, each dispatched as the request that opened its own socket and never as the other, with an unstamped socket yielding no request at all rather than its neighbour's; and the same claim through a real browser. Those tests live in our repository, not here — upstream homes would bepackages/api/gateway/tests/stream-server.host.spec.tsandgateway-stream.host.spec.ts, and we would write them if there is appetite.All reactions