Skip to content

Some thoughts on the durable event iterator package #993

@marbemac

Description

@marbemac

Describe the feature

Hi, we've been digging into the experimental durable event iterator package recently, and I just noticed you're actively working on it in https://github.com/unnoq/orpc/pull/965, so I thought to maybe see what you think of the thoughts below.

We're really liking the relatively simple setup w type safety, from client <-> durable object, for both events and rpc calls.

However, we don't need the "durable" (sqlite) functionality - at least not how it's currently implemented. What do you think about maybe making all of the sqlite stuff opt-in, and exposing an onConnect method?

We've got the classic stream llm tokens use case. Stream tokens over the socket while it's in flight, and once the stream is done we squash the parts and and persist them to postgres. So while the llm call is ongoing, the stream is the source of truth for the client, and once the llm call is done postgres becomes the source of truth for that message.

So on the durable object side we just need some simple in memory state for messages that are actively streaming, which we could manage if we had an onConnect method and a means of setting our own event ids etc, like the base event iterator stuff.

Very rough example:

class MyDurableObject {
  #inMemoryEvents: Events[] = [];

  onConnect(ws: WebSocket, { context, lastEventId }) {
    const relevantEvents = getThem(lastEventId); // our logic for getting the events
    for (const evt of relevantEvents) {
      this.dei.websocketManager.publishEvent([ws], evt);
    }
  }

  // our publish method
  #publish(evt: Event) {
    if (evt.type === 'llm-end') {
      // cleanup relevant #inMemoryEvents for this message.. it's done and will be served from postgres now
    } else {
      this.#inMemoryEvents.push(evt);
    }

    // set our own event ids, like base sse approach
    this.dei.websocketManager.publishEvent(this.ctx.getWebSockets(), withEventMeta(evt, { id: evt.id }));
  }
}

Or maybe it would be enough if we could pass our own DurableEventIteratorObjectEventStorage in, I'm not sure.

Overall the durable-event-iterator package brings a lot more to the table DX wise than just the "durable"/sqlite persistence piece, and we'd love to be able to use all of that without the sqlite insert/delete delete operations on every event, which is overkill for our use cases.

Side note: the RpcTarget approach is super nice because it avoids having to subclass - thus won't conflict if one is already extending something else, etc. And can still support migrations, etc - example here -> https://github.com/benallfree/dofs/blob/main/packages/dofs/src/Fs.ts.

Additional information

  • Would you be willing to help implement this feature?

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions