$12k a year saved with vx vs Nx Cloud
$12k a year saved with vx vs Nx Cloud
vx's CI is one run spread over its own Linux and Mac runners. On Nx Cloud's Team plan with Nx's agents, the same CI would cost about $12,192 a year. On vx it costs $0.
vx DTE's relay keeps no message. It passes frames between sockets, and the two ends make sure each one lands.
The relay behind vx DTE keeps no message. It stores only who takes part, one row each, so a restart keeps the run. A quiet run of four sockets sends 60 frames through it in ten heartbeats.
flowchart LR O[orchestrator] <-->|"socket: numbered, acked"| R((relay)) R <-->|"socket: numbered, acked"| W1["worker small#1"] R <-->|"socket: numbered, acked"| W2["worker small#2"]
Each side opens one websocket and joins on it, with its CI OIDC token. There is no other route. A refused join gets its socket closed, with the reason in the last frame and in the close.
sequenceDiagram participant O as orchestrator participant R as relay participant W as worker O->>R: message 7, an order R--xW: socket gone, dropped Note over O: no ack after a heartbeat O->>R: message 7, again R->>W: message 7 W->>R: ack 7 R->>O: ack 7
The relay pushes a message down the receiver’s socket, or drops it. Each side numbers what it sends and sends it again until the other acks it. The receiver takes each number once, in order.
xychart-beta title "Frames, quiet run, 4 sockets, 10 heartbeats" x-axis ["relay pings every socket", "peers probe only the quiet"] y-axis "frames" 0 --> 100 bar [92, 60]
1 orchestrator, 3 idle workers · 88-96 frames before, 24 up and 36 down after (#4309)
When a socket closes, the relay drops its worker at once. A worker that goes quiet on an open socket is asked after 1.5 heartbeats. No answer, and it is lost in under 10 s. When the orchestrator’s socket closes, every worker’s closes too.
On Cloudflare the run is one Durable Object, there only to hold its sockets. What a woken object needs rides on each socket, and who takes part is one row each, so a deploy keeps the run. A join costs one request, and every 20 websocket messages count as one more.
docker build -t vx-dte-server packages/vx-dte-serverdocker run -p 8080:8080 vx-dte-server --allow https://gitlab.com:group/app:.gitlab-ci.yml --audience https://relay.example.comThe container is the same relay on Bun. With --state on a volume, a
restart keeps its runs too. CI builds the image and carries a run
through it and across docker restart (test.live).
Relay README · more at vznjs.github.io/vx.