Malik SohaibEmail me
← All work

Photon to Elixir

Real-time room and file sync moved off a busy Node server onto Phoenix Channels.

Role
Senior Full Stack Engineer at Arthur
Status
Shipped

A portal kept room lists and per-room file lists in sync with Photon. An Express server held the snapshot in memory and pushed changes to browsers over server-sent events.

Every user held two long-lived streams for the room lists, plus one per open room. That traffic shared the same Node process as the rest of the API, and slowed it down.

Decisions

  1. 01

    A dedicated Elixir service

    Chose
    Move sync into Elixir, with Phoenix Channels to the browsers.
    Instead of
    Scaling the Express server or adding more SSE workers.
    Why
    Channels are built for many long-lived connections, and the BEAM keeps them cheap and isolated from the rest of the API.
  2. 02

    Our own Photon client

    Chose
    Write a Photon client in Elixir, using the JavaScript SDK as the reference.
    Instead of
    Keeping the JavaScript SDK and bridging to it from Node.
    Why
    It removed Node from the sync path completely, so the protocol and the fan-out live in one runtime.
  3. 03

    Hot state in ETS

    Chose
    Keep inactive rooms, active rooms and file lists in ETS tables.
    Instead of
    Reading MongoDB on every push.
    Why
    Pushes read memory, not the database. MongoDB stays the durable copy.
  4. 04

    One codebase, two clouds

    Chose
    Hide cloud differences behind adapters.
    Instead of
    A fork of the service per cloud.
    Why
    The same build runs in five environments across AWS and GCP.

What shipped

  • Sync no longer competes with the API for the Node event loop.
  • Channel topics enforce the same access rules the SSE endpoints had.
  • Repeatable Docker-based releases across five environments on two clouds.

Built with

Elixir, Phoenix Channels, ETS, Photon, MongoDB, Docker Compose, AWS, GCP

Some details are kept general on purpose.