Skip to content

Port to Eio and Cohttp - #327

Draft
aantron wants to merge 4 commits into
masterfrom
cohttp-eio
Draft

Port to Eio and Cohttp#327
aantron wants to merge 4 commits into
masterfrom
cohttp-eio

Conversation

@aantron

@aantron aantron commented Jul 3, 2024

Copy link
Copy Markdown
Collaborator

This is a messy draft port of Dream to Eio using cohttp-eio. On HTTP/1, it works better than the previous port attempts (#254, #194) and should be more maintainable, including because cohttp-eio offers a direct-style interface (the advantages of which this port still needs to propagate further into the Dream code), but a lot of features will be missing even after the port is complete -- HTTP/2 support, GraphQL, and others, because the corresponding libraries are not ported to Eio or not available with Cohttp. A lot of features, like Caqti integration, that will be available when this port is done, are temporarily disabled for now, and will be added back as the port progresses. WebSockets will require additional work.

The current status of the port is that I am working through various deadlocks and corner cases of using Eio "promises" together with fibers, which are caused by the existing code of Dream assuming a sort of promise-callback soup, where any callback can be called on the one big stack under Lwt.main and make progress, while with fibers and Eio blocking the wrong fiber to wait on a promise can block a stack that would have been used to make progress to resolve that promise. The semantics are therefore substantially different. This was a major problem with the approach in #194 and #254. It is substantially negated by thoroughly using direct style wherever possible, rather than promises or callbacks.

aantron added 4 commits May 30, 2024 13:13
Due to over-confident naming of top-level module Http from Cohttp.
@smorimoto

Copy link
Copy Markdown

Comment thread example/3-router/dune
(executable
(name router)
(libraries dream))
(libraries dream eio_main))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't eio_main get pulled in transitively by dream? In the same way that lwt.unix was before.

Comment thread src/dream.mli
string -> response
(** Same as {!Dream.val-response}, but the new {!type-response} is wrapped in a
{!type-promise}. *)
(* TODO Remove, or remove response. *)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO it would be easier on users to remove response as most like respond is used a lot more.

Comment thread src/dream.mli
?port:int ->
?socket_path:string ->
?stop:unit promise ->
?stop:unit -> (* TODO What should this be? And fix the docs. *)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/http/driver.ml
single_read stream destination
|> Eio.Promise.resolve_ok resolver
end
~flush:(fun () -> chunk_loop ())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be just ~flush:chunk_loop

Comment thread src/http/driver.ml
Log.set_up_exception_hook ();
ignore user's_error_handler;

let httpaf_request_handler

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this name be changed?

Comment thread src/http/driver.ml
address
in

(* TODO Value of the backlog argument? *)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like backlog should be around 128: https://stackoverflow.com/a/36452474/20371

Comment thread src/pure/message.ml
| Response -> message.client_stream <- Stream.string body

let set_content_length_headers message =
(* TODO Restore.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we can use Eio.Promise.peek to do something similar to Lwt.poll here?

Comment thread src/pure/stream.mli

type buffer =
(char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t
type 'a promise =

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ironically, we could probably do type 'a promise = 'a Eio.Promise.t here.

Comment thread src/server/log.ml

(* Lwt sequence-associated storage key used to pass request ids for use when
~request is not provided. *)
(* TODO Is there an equivalent mechanism with Eio?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like yes: https://ocaml-multicore.github.io/eio/eio/Eio/Fiber/index.html#fiber-local-variables

Fiber-local variables are particularly useful for attaching extra information for debugging, such as a request ID that the log system can include in all logged messages.

Comment thread src/server/log.ml


let set_up_exception_hook () =
(* TODO Is there an Eio equivalent?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think no, because to my understanding every fiber in Eio propagates its exceptions upwards to its parent fibers and eventually up to the root fiber.

Comment thread dream.opam
"mirage-crypto-rng-eio"
"multipart_form" {>= "0.4.0"}
"multipart_form-lwt"
"ocaml" {>= "4.08.0"}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can just remove the OCaml version since Eio will force >5

@yawaramin

yawaramin commented Dec 26, 2024

Copy link
Copy Markdown
Member

Trying to see if I can get this branch to run. There's been some bitrot, especially the Mirage folks have gotten rid of cstruct and moved to string/bytes. Hacking and slashing now...

EDIT: pushing my changes to https://github.com/yawaramin/dream/tree/cohttp-eio

The examples are running now. Will play around with it a bit more.

@kognise

kognise commented Feb 20, 2025

Copy link
Copy Markdown

I think this is super important, is there any way I can help speed up the work to port dream to eio?

@clauverjat-h

clauverjat-h commented Mar 4, 2025

Copy link
Copy Markdown

Hello @yawaramin

I tried to play with your fork, but I got the following error

Context: _private                        
File "src/http/dune", line 11, characters 2-10:
11 |   eio_main
       ^^^^^^^^
Error: Library "eio_main" not found.
-> required by library "dream.http" in _build/default/src/http
-> required by _build/default/META.dream
-> required by _build/install/default/lib/dream/META
-> required by _build/default/dream.install
-> required by alias install

To fix the issue I needed to replace eio_main by eio in src/http/dune

Note: I edited the message, I had other issues before but they were due to some misunderstanding on my part regarding dune package management, so nothing to do with your code.

@Willenbrink

Copy link
Copy Markdown
Collaborator

Just want to put out there that I have fixed some of the issues in yawaramin's fork which can be found here: https://github.com/Willenbrink/dream/tree/cohttp-eio.

All the tests pass and the examples we looked at work too. I've also rebased the changes on top of the additional tests I've written in #396 which also pass.

@yawaramin

Copy link
Copy Markdown
Member

@Willenbrink great work! Checking out your fork.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

6 participants