Stream: API design

Topic: Persistent Connections


view this post on Zulip Brendan Hansknecht (Jul 05 2024 at 23:32):

Do we have any plans around persistent connections and in general persistent data in basic-webserver?

For example, as I am thinking about improving the sqlite api, one thing that would be nice is being able to initialize a prepared statement once and then reload the same prepared statement on every request. That removes the need to repeatedly pass around and parse strings.

The same could be wanted from roc-pg with tcp connections.


Do we already have a plan of how we want to support things like this?

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:13):

vaguely yeah

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:13):

it's the same idea as what I think we should do for "streams" (aka wrappers around file descriptors)

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:14):

basic idea is that in Roc it's represented as an opaque wrapper around a Box {}

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:14):

but the critical aspect is that you can only get one of those things from the host

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:14):

and the host allocates that box in a separate arena from the rest of the heap

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:15):

so that when it gets passed to roc_dealloc you can check its address range and see if it's in the special arena, and if so, go look up its address in a hash to figure out what cleanup to do

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:16):

so the general theme in both cases is "platform gives you a value that is associated in the host with some persistent state that needs to be cleaned up when there are no more references to it"

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:16):

such as an open file or an open tcp connection

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:17):

separately, if we want to have basic-webserver support a concept of "run this initialization thing once, and then that gives you a value that can be handed off to every request" - unfortunately I think that requires passing records of functions to the host, which @Folkert de Vries and I have not succeeded in getting working yet, even when Boxing the functions

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:18):

because I think we'd need to do something like giving the host separate init and handleRequest functions in the same record, so they can share type variables

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:19):

e.g.

{
    init : {} -> Task state [],
    handleReq : Request, state -> Task Response [],
}

view this post on Zulip Brendan Hansknecht (Jul 06 2024 at 01:19):

So I understand the platform side of the lifetimes, but how can something be kept alive across many requests.

Ex. examples/sqlite3.roc has a query "SELECT id, task FROM todos WHERE status = :status;".
For best performance, the goal would be to prepare that query once per thread.
Then on every request have roc be able to get the Box {} for the prepared query (preferably without using the string at all).

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:19):

oh I guess maybe it could work if you did something like Model

view this post on Zulip Brendan Hansknecht (Jul 06 2024 at 01:20):

So it is more a connection pool question than a connection lifetime question.

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:21):

Brendan Hansknecht said:

how can something be kept alive across many requests
[...]
For best performance, the goal would be to prepare that query once per thread.
Then on every request have roc be able to get the Box {} for the prepared query (preferably without using the string at all).

yeah I think that's where the init concept comes in

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:21):

well, that wouldn't understand pooling I guess

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:21):

I guess we could introduce a generic "pooling" concept

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:21):

(that is, basic-webserver could)

view this post on Zulip Brendan Hansknecht (Jul 06 2024 at 01:22):

well, that wouldn't understand pooling I guess

You could init per thread and it would at least be decent. Maybe a tad wasteful, but functional.

view this post on Zulip Richard Feldman (Jul 06 2024 at 01:22):

where you can define a Pool a that knows how to hand things out

view this post on Zulip Brendan Hansknecht (Jul 06 2024 at 01:52):

Quick aside: I don't think Box {} works in roc currently. At least not fully. I was originally using it for some of my ffi stuff instead of U64. Was hitting weird unification errors.

view this post on Zulip Brendan Hansknecht (Jul 06 2024 at 01:52):

Need to try and build minimal repros at some point.

view this post on Zulip Brendan Hansknecht (Jul 06 2024 at 02:16):

For Box {}. Is the thought that I would actually have Box SomePlatformType? So you have to throw whatever connection/prepared stmt/etc type into a box. Just don't tell roc about the type inside.

That said, I would assume that roc shouldn't actually refcount a box of a zero sized type like {}. Like it should just never allocate it or anything. But maybe this is useful in practice, so we just Box {} to be a box of something unknown to roc and still have it refcount and attempt to free the thing.

view this post on Zulip Richard Feldman (Jul 06 2024 at 10:43):

hm maybe!

view this post on Zulip Richard Feldman (Jul 06 2024 at 10:43):

the thought was that for a file descriptor, Box I32 would be worse than (I32, Box {}) because now you have to chase a pointer to access the fd

view this post on Zulip Brendan Hansknecht (Jul 06 2024 at 16:37):

That's fair. With (I32, Box {}), there is still 8 bytes randomly on the heap, but it is only accessed for refcounting.

view this post on Zulip Richard Feldman (Jul 06 2024 at 18:44):

yeah and I assume if you ask for this it’s because you’re planning to pass it multiple times to things


Last updated: Jul 06 2025 at 12:14 UTC