Skip to content

feat(examples): realtime session queue reference (server gate + web client)#187

Merged
AdirAmsalem merged 11 commits into
mainfrom
customer-session-queue-design
Jul 22, 2026
Merged

feat(examples): realtime session queue reference (server gate + web client)#187
AdirAmsalem merged 11 commits into
mainfrom
customer-session-queue-design

Conversation

@AdirAmsalem

@AdirAmsalem AdirAmsalem commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Customers with a realtime concurrency limit (say, 10 sessions) need a product answer for the 11th user: wait in a fair line with live position feedback, instead of a failed connection. This PR adds examples/realtime-session-queue — a runnable reference showing how to build that gate on your own backend, in front of client.realtime.connect(). The scenario modeled is a virtual try-on experience (lucy-vton-latest), but the pattern applies to any capacity-limited realtime model.

The idea

Your backend already holds the API key and mints ephemeral client tokens for your app. A session queue is nothing more than deciding when to mint the next token:

App                        Your gatekeeper (this example)              Decart
 │  POST /api/queue/tickets  │                                           │
 ├──────────────────────────>│ enqueue                                   │
 │   { ticketId, position }  │                                           │
 │  POST .../poll (every 2s) │                                           │
 ├──────────────────────────>│ waiting → { position, queueSize }         │
 │          ...              │                                           │
 ├──────────────────────────>│ head of line + free slot?                 │
 │                           ├── tokens.create(expiresIn, maxSessionDuration)
 │   { state: "ready",       │<──────────────────────────────────────────┤
 │     session: { apiKey } } │                                           │
 │<──────────────────────────┤                                           │
 │  realtime.connect(apiKey) — WebSocket + WebRTC, key never in the app  │
 ├───────────────────────────────────────────────────────────────────────>
 │  POST .../started once connected                                      │
 │  POST .../release { reason } when done                                │

Three properties make it robust without being clever:

  1. The token is the no-show timeout — its expiresIn matches the queue's 45s claim grace (the connect window); a granted user who never connects loses nothing for anyone else.
  2. Decart enforces the session cap — the token carries constraints: { realtime: { maxSessionDuration } }, so a backgrounded or killed app can never squat a slot and the line always moves.
  3. Decart is the backstop for races — if a connect is still refused at the limit (WS close 1013), the app reports it and the ticket is requeued at the head of the line, so the user keeps their place.

Every join takes its own spot: capacity limits concurrent sessions, not users.

Try it

pnpm install && pnpm --filter @decartai/sdk build
cd examples/realtime-session-queue
cp .env.example .env       # add your DECART_API_KEY
pnpm dev                   # gatekeeper on :3000, web app on :5173

Open two tabs and hit Try it on in each (a sample garment is preloaded). With QUEUE_CAPACITY=1, the second tab waits with a live position and inherits the slot the moment the first session ends.

What's inside

  • server/queue.ts — the whole algorithm in one file: FIFO line + capacity-bounded leases, with time and token-minting injected so the tests are instant and deterministic (12 tests).
  • server/main.ts — the five-route HTTP protocol (join / poll-as-claim / started / release / stats).
  • web/ — a React client whose useQueue hook uses only fetch, timers, and React state.
  • README covering the protocol, the slot lifecycle, and a hardening checklist for production (auth, multi-instance shared store, heartbeats, wait estimates).

Verified live end-to-end against a limit-3 test account: real try-on sessions, queue position → slot handover between users, and automatic recovery through the over-limit backstop.


Note

Low Risk
Changes are confined to examples and lockfile; no SDK or production runtime behavior is modified.

Overview
Adds examples/realtime-session-queue, a runnable pattern for fair waiting lines when realtime concurrency is capped: users join with a ticket, poll for position, and only then receive a short-lived ephemeral token to call realtime.connect() (virtual try-on on lucy-vton-latest).

The Express gatekeeper wires Queue to tokens.create() with a 45s connect window and maxSessionDuration on the token, plus HTTP routes for join, poll-as-claim, started, release (ended / limit_reached requeue-at-head), and stats. server/queue.ts holds FIFO waiting, capacity leases, no-show reclaim, and mint races; 12 Node tests cover the semantics with injected time/mint.

The Vite/React client uses a useQueue hook (fetch + polling) and TryOnSession for camera + realtime, including 1013 / session-limit handling that reports limit_reached back to the server. A long README documents protocol, slot lifecycle, and production hardening.

Elsewhere the diff is cosmetic: import order / formatting in a few examples, trailing newline cleanup, and pnpm-lock.yaml entries for the new workspace example (plus unrelated lockfile churn).

Reviewed by Cursor Bugbot for commit 1e20fe5. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread examples/realtime-session-queue/server/queue.ts
Comment thread examples/realtime-session-queue/web/src/hooks/useQueue.ts
@pkg-pr-new

pkg-pr-new Bot commented Jul 22, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@decartai/sdk@187

commit: 1e20fe5

Comment thread examples/realtime-session-queue/server/queue.ts Outdated
Comment thread examples/realtime-session-queue/server/queue.ts
Comment thread examples/realtime-session-queue/web/src/hooks/useQueue.ts
Comment thread examples/realtime-session-queue/web/src/hooks/useQueue.ts Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 83ac1d7. Configure here.

Comment thread examples/realtime-session-queue/server/main.ts Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7b00715. Configure here.

Comment thread examples/realtime-session-queue/server/queue.ts
Comment thread examples/realtime-session-queue/server/queue.ts
@AdirAmsalem
AdirAmsalem merged commit ae780dc into main Jul 22, 2026
5 checks passed
@AdirAmsalem
AdirAmsalem deleted the customer-session-queue-design branch July 22, 2026 10:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant