spin icon indicating copy to clipboard operation
spin copied to clipboard

HTTPS Connection reuse from Spin worker

Open dlozina opened this issue 1 year ago • 7 comments

Hi all, I am looking into possibly having two outbound HTTPS calls from my Spin worker or Webasembly module in general to the same server and reusing the connection. It would be beneficial so we don't have to do a handshake to the server again, and requests over the network would be faster for that use-case. If I understood correctly, there is no technical reason why we can't support connection reuse with wasi-http, I have not found a good code example of the implementation for that use case. Is this something that is planned to be implemented in Spin? Could you please point me to some examples that cover this use case? Thank you!

dlozina avatar Apr 09 '24 09:04 dlozina

@dicej Is this something @dlozina could access by wit-bindgen-ing the wasi-http outgoing-handler interface directly into their project, or is it something the Spin host would need to (invisibly) do?

itowlson avatar Apr 09 '24 19:04 itowlson

This requires a Spin change. Currently, we use the default outgoing request handler provided by wasmtime-wasi-http (https://github.com/fermyon/spin/blob/b86af6c7188e84f5824f7eef757c65ff2ad265c4/crates/core/src/lib.rs#L236), which creates a new TCP connection and sends the request using hyper: https://github.com/bytecodealliance/wasmtime/blob/de0a9d7ce959d83a336d4f13487cf00e69e9efb2/crates/wasi-http/src/types.rs#L114. In order to reuse requests, we'd need to provide our own handler instead.

One appealing option would be to use reqwest, which has built-in support for connection pooling. However, as of this writing it does not yet support trailers, which means it can't be used to fully implement wasi:http/outgoing-handler. Using trailers is pretty rare in the real world, though, so perhaps that's an acceptable tradeoff.

dicej avatar Apr 09 '24 21:04 dicej

Hi @itowlson and @dicej , first of all thank you for the extremely fast response! 🙏🏻 I agree with @dicej , trailer support is not a dealbreaker ATM. @dicej does this boils down changing hyper with reqwest?

dlozina avatar Apr 10 '24 10:04 dlozina

@dlozina We'll need to create an outgoing http implementation from scratch based on reqwest instead of using the one provided by wasmtime-wasi-http, which is based on hyper. It shouldn't be terribly difficult. FWIW, I created one for wasi:[email protected] which we could use as a starting point: https://github.com/dicej/isyswasfa/blob/df9a153fafbbdf532d811bdc53e61ff7368e4898/cli/src/main.rs#L126-L244

BTW, @lann has done a bit of research, and it looks like adding basic trailer support to reqwest could be pretty easy.

dicej avatar Apr 10 '24 13:04 dicej

That is great! Thank you @dicej How can I help? This is not something I have done before but I am willing to learn and put in the work.

dlozina avatar Apr 10 '24 13:04 dlozina

@dlozina If you want to try making a PR for this, the code should go here: https://github.com/fermyon/spin/blob/b86af6c7188e84f5824f7eef757c65ff2ad265c4/crates/trigger-http/src/lib.rs#L694. You'll want to replace the wasmtime_wasi_http::types::default_send_request(data, request) line with code that translates the wasmtime_wasi_http::types::OutgoingRequest into a reqwest::Client::request call similar to the code I linked to above, and then translate the resulting response into a wasmtime_wasi_http::types::HostFutureIncomingResponse. The key to making reqwest reuse connections is to reuse a reqwest::Client instance, which means you'll want to add that as a field to the HttpRuntimeData struct in that file.

dicej avatar Apr 10 '24 13:04 dicej

@dicej thanks for the instructions and help! 🙏🏻

dlozina avatar Apr 10 '24 16:04 dlozina