Effect CommunityEC
Effect Community2mo ago
1 reply
Jan Wilhelm

**Modeling Live-Update Functionality with Effect Atom for Chat**

Does anyone have some rough ideas for how to model this type of live-update functionality using Effect Atom?

Say I have a model called "Chat". A chat can have multiple messages. I want to ensure that while the chat is "open", I consume "update events" for that chat and apply them to the chat. Update events could, for example, be live chat messages someone is sending.

These events will be consumed via something like WebSockets or SSE. While the chat is "open", refetching it from the backend will return the latest persisted version of the chat, where the "update events" (e.g. chat messages) haven't been persisted yet.

In my atoms, I have an Atom family getBackendChatByIdAtom that is quite trivial - it just fetches the chat from the backend via HTTP. Separately, I have a ChatUpdateService effect service with streamChatUpdates(chatId) => Stream<ChatUpdateEvent>.

Now, I want to somehow wrap the getBackendChatByIdAtom atom in another atom that optimistically merges the stream of Chat Updates and the backend-returned latest snapshot of the Chat into a chat that I render on the frontend. To achieve that, I've thought of an API somewhat like

const combinedChatStateAtom = Atom.family((chatId: string) =>
  runtime.atom((get: Atom.Context) =>
    Effect.gen(function* () {
      const backendState = yield* get.result(getBackendChatByIdAtom(chatId));

      if (backendState.status === "open") {
        const chatUpdateService = yield* ChatUpdateService;
        // initialize the stream here, somehow merge the events with the backend state
        // return the merged stream
      } else {
        return backendState
      }
    })
  )
);


I need to make sure that there is only ever one stream connection open per chat, because otherwise we'd see messages twice. I also want the stream to stay open when the combinedChatStateAtom is currently not used, so I can show a toast per msg.

I know this is specific, but would really appreciate any guidance here! ❤️
Was this page helpful?