Hi Torste,

Wow, to be honest, I don't think I really expected anyone to get this far
this quickly. :)

I think the problem is indeed that your server is exiting the process
before it has actually fully responded to the HTTP request. If it were a
regular kj::HttpServer, I think your code would work as-is, but RPC adds
some additional "stuff" happening asynchronously that doesn't get a chance
to finish.

If you skip the "EZ RPC" classes and instead use the slightly-lower-level
capnp::TwoPartyServer, there is actually a method called drain() which
waits for all clients to disconnect. That could help you here... maybe. If
your client is nice and voluntarily disconnects after sending the exit()
command, this works. If not, though, things are harder. You want to
force-disconnect them, but only after the HTTP interaction has completed, I
guess.

I'm not sure there is a satisfying answer right now. You could use
membranes (capnp/membrane.h) to write a wrapper that tracks how many RPC
calls are actively in-flight, and then exit when it reaches zero? It's
possible but would be overcomplicated, I think.

The tricky part about adding a generic feature for this is that it seems
like it needs to distinguish between capabilities that represent an active
ongoing operation, vs. capabilities that are held idly. Like, you might
hold on to an HttpService capability forever, just in case you need to call
it. That shouldn't block shutdown. But if you've begun a call and are
holding a ServerRequestContext capability waiting for a response, than
should force the server to stay up until the response is sent, I think?

This ties in with something I don't like about the http-over-capnp protocol
at it stands: you call startRequest() to start a request, but that actually
returns immediately, giving you a ServerRequestContext object that
represents the ongoing request. You drop that object to cancel the request.
It would be more intuitive if you called a method `request()` and that
method didn't actually "return" until the entire request/response was done.

However, at present that doesn't work, because in order for the server to
start receiving the request body, it has to return a stream to use (the
`requestBody` field of startRequest()'s result). But, promise pipelining
means the client may actually start sending calls to this capability before
the server has returned it. The hold-up is really an implementation detail
entirely on the server side: there's no way for the server to start seeing
those queued requests until it has returned from the call.

Maybe we could add some API by which the server could say "I'm not done
yet, but go ahead and start sending pipelined calls to this capability"?
Then we'd be able to define this protocol in a nicer way...

... and then, your "drain" rule could actually be strictly "no calls in
flight", disregarding any live capabilities.

-Kenton

On Sat, May 2, 2020 at 6:57 PM <zok...@gmail.com> wrote:

> Hi,
>
> I was playing around with the new HTTP over capnp feature in 0.8.0, and
> one oddity I stumbled upon is that there doesn't seem to be a easy way to
> drain outstanding requests when shutting down. I think this is best
> demonstrated by small code example.
>
> I have this very simple kj::HttpService that I'm exposing through
> capnp-rpc:
> https://github.com/zokier/capnp-stdio-proxy/blob/master/hello-server.cpp
> and corresponding client
> https://github.com/zokier/capnp-stdio-proxy/blob/master/proxy-client.cpp
>
> When I curl http://localhost:8080/exit the service does exit, but the
> response body never makes it through. The error message I see from my
> "proxy-client" is:
>
>     kj/compat/http.c++:5079: error: unhandled exception in HTTP server;
> exception = kj/compat/http.c++:1852: failed: previous HTTP message body
> incomplete; can't write more messages
>
> To me it seems like the server exits before the client manages to fetch
> the response body, which is obviously not good. I'm not sure if the problem
> is that the promise from line 24 `response.sendError(200, "OK", headers)`
> resolves too early, or if the HttpOverCapnp thingy needs some explicit way
> to drain the server.
>
> As a side-note I noticed that the http-over-capnp files were not included
> in the release tarball, I needed to poke around bit in Makefile.am and git
> checkout to get those installed. No biggie, but I imagine you'll want to
> get that fixed for next release.
>
> /Torste Aikio
>
> --
> You received this message because you are subscribed to the Google Groups
> "Cap'n Proto" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to capnproto+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/capnproto/c16d69d1-5803-4dbe-8666-742de8641a50%40googlegroups.com
> <https://groups.google.com/d/msgid/capnproto/c16d69d1-5803-4dbe-8666-742de8641a50%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
>

-- 
You received this message because you are subscribed to the Google Groups 
"Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to capnproto+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/capnproto/CAJouXQ%3Dorx3m2F40bEPSEAfy7K%2BtCLmSodArqoP83EXhCmu2dA%40mail.gmail.com.

Reply via email to