-
Notifications
You must be signed in to change notification settings - Fork 81
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
Plug.Conn.send_resp
in separate process fails for HTTP/2 streams
#101
Comments
Plug.Conn.send_resp
in separate process fails for HTTP/2 streams
That's an oddball one! I suppose the plug API doesn't specify anything explicitly about cross-process plug usage, but it conceptually seems like doing so could introduce a ton of gnarly concurrency issues. |
Brought it up on the forum: https://elixirforum.com/t/are-there-restrictions-on-making-plug-conn-calls-across-multiple-processes/54088/1. Let's see what people say. |
Great! Yeah, maybe this is just an extreme edge case, and it was never really meant to handle the conn outside of the owner process. I can't think of any other library that would do this other than bypass. I looked at the plug sourcecode. The https://github.com/elixir-plug/plug/blob/d7940552e365e0d3245bb78ca99429ea5c324f7d/lib/plug/conn.ex#L447-L455 The test conn is interesting, sending messages to the owner pid (I want to dig into where the test conn is used): https://github.com/elixir-plug/plug/blob/12dbfb817d1951c955afe90d0f4f4bf4bfd4e8b9/lib/plug/adapters/test/conn.ex AFAIK it's used for Phoenix ConnTest, but I'm guessing everything happens in the same test process there. |
FWIW I pushed this PR danschultzer/test_server#9 where I experience the issue (I realized I wasn't testing HTTP/2 streams). When I got more time I'll dig deeper into how the owner pid attribute is used in plug. |
Forum post was inconclusive; not really much to do here. |
I've had issues with gRPC/Gun across processes, too. Instead of trying to understand it, I just rewrote that part. Smol-brained solutions. |
I've thought a lot more about this trying to figure out how this should be solved in TestServer. Since the Another thing is that
And as I said earlier, the conn test adapter also sends the message back to the controlling process: I think how Bandit should work is to send the message back to the controlling process rather than just ignoring the message. A question I got; isn't that already kinda what happens with the @josevalim I would appreciate any input here if you got some insights on how to treat the conn.owner attribute when dealing with the conn callbacks 😄 |
I solved this in I also opened #115 to surface the controlling process error with a warning. It'll still be good to have a more definite answer on the correct approach with controlling process for the conn, but my issue is solved (as long as nobody calls |
I added the sending PID constraint code mostly as a footgun suppressant if people were to try calling from multiple processes. Rather than leave open the possibility of oddball concurrency issues, I figured I would enforce a strict owner process constraint, which is what you see here. That said, I'm 90% sure that it isn't strictly required; I could drop the owner constraint & things would function just fine; we'd basically have the same level of concurrency issue resilience that Cowboy / Plug has in this regard. I'm quite open to that. I've pushed up an implementation of this as #117. Have a look; I think it would simplify a bunch of the issues folks have been having with this, and concedes only on points I don't feel too strongly about. |
I added a note on #215 about upcoming changes to how we do PID checking that will apply here as well |
Took me a while to track this one down. When testing with HTTP/2 I was seeing failure with
Stream 3 completed in unexpected state remote_closed
and empty responses even though I definitely did send the response!The culprit is this line (the same for
send_data
):bandit/lib/bandit/http2/connection.ex
Line 365 in ebba77a
In TestServer the route matching lives in a GenServer. When a requests hits the generic plug on the HTTP server, the plug will pass off the conn to the genserver to be processed in a
handle_call
callback. This means that caller pid will be different when callingsend_resp
.Resolving this in TestServer may be awkward since the routing state lives in that GenServer process. Maybe it does make sense that the
send_resp
call should only happen in the generic plug process. But what's the reasoning behind theowner?/2
check? Why is it necessary to lock the conn processing to the initial caller?FWIW cowboy works with the current logic in TestServer. It works as expected with Bandit when I remove this check, but not sure if there are any sideeffects to doing that. If it's necessary to have this check then it would be good to have a clearer warning.
The text was updated successfully, but these errors were encountered: