An Eight Mile service · private

QueueOps

A virtual waiting room for ticket on-sales. Your platform opens a room for each sale and sends its signed-in buyers to join. QueueOps puts them in a fair order, lets them in at the pace the sale can take, and gives each one a signed admission your platform checks itself, so a sale under way does not depend on QueueOps staying up.

Runtime

TypeScript · Redis

Engine

Lua · atomic

Admission

ES256 · local check

Tests

243 · real Redis

one sale

wait → admit → check

WAITING · FRONT FIRST1234567EVERY 1 SIN THE SALEMAX ACTIVEES256admissionyour platform checks it

Why a waiting room

An on-sale is a crowd arriving at once.

When a big match goes on sale, thousands of buyers arrive in the same minute. Let them all at the seat map and it slows for everyone, and whoever refreshes fastest gets the seats. A waiting room holds the crowd outside, puts it in order and lets people in as fast as the sale can serve them.

A fair order

Arriving first before the sale is no edge.

Everyone who joins before the sale opens holds a place in a random order, drawn when the sale opens. Anyone who joins after that goes to the back, in the order they arrived. A waiting buyer’s position only ever goes down.

A pace the sale can take

Only so many shop at once.

You set how many buyers can be in the sale together. Every second, QueueOps lets in as many from the front as there are free slots, and never more, however many copies of it are running.

One place per person

Refreshing does not buy a second place.

A person has one place and one turn, and joining again hands back the place they hold. A room has a capacity and each address a limit, both checked in the step that gives the place. Joining goes only through your platform, after its own checks, so a bot cannot join QueueOps directly.

A sale that keeps selling

Your checkout never calls QueueOps.

An admitted buyer carries a signed token, and your platform checks it with keys it pinned beforehand. If QueueOps went down mid-sale, buyers already let in would keep buying, and new joins would be refused rather than guessed at.

A buyer’s path

Six states, and a position that only goes down.

The browser asks where it stands, and the answer says how long to wait before asking again: often near the front, rarely far back, each interval spread a little so a crowd that joined together does not ask together. A browser that asks too soon is turned away before the database is touched.

State

What the buyer is told

Asks again

pre_sale

Has a place

Joined before the sale. No position yet, because the order is drawn when the sale opens.

~30 s

waiting

In the queue

A position, how many are still waiting, and an estimated wait once the room’s pace has been measured.

3–15 s

admitted

In the sale

Holds a signed admission until its time is up, and the platform lets them reserve with it. Finishing early gives the slot to the next buyer.

~30 s

expired

Turn ended

The admission ran out. The place stays spent.

~60 s

left

Left

Left the queue, or finished and gave the slot back.

~60 s

closed

Room closed

The room was switched off or is gone. The buyer joins again through the platform.

~60 s

What you set for each sale

Nine settings, all of them sent on every save.

A room is one call with every field in it, so a retry or a re-sync is the same call again and a typo is refused rather than dropped. Changes to a live room apply at once: more capacity lets more people join, and a new pace applies from the next second.

SettingWhat it decidesAllowed

capacity

The most people who can ever hold a place. It can be raised on a live room.

1 to 1,000,000

queueOpensAt

When joining opens.

before the sale

saleOpensAt

When the order is drawn and admissions start.

before expiry

maxActive

How many shop at once. A change applies on the next tick.

1 to 100,000

maxPerClientKey

How many places one address can take.

1 to 1,000,000, or none

admissionTtlSeconds

How long an admitted buyer has to finish.

30 s to 1 hour

expiresAt

When QueueOps forgets the room and everything in it.

in the future

status

Closed means no joins and no admissions, kept until it expires.

active or closed

version

A higher one replaces the room, an equal one is applied again, a lower one is ignored.

a positive integer

How a platform plugs in

Six steps, and only one of them is ours.

QueueOps knows nothing about events, seats or customers: a room is your id for the sale, a visitor your id for the person, and an address an opaque hash. Any platform with an account can use it, and TicketOps is the first.

01

An account

We make your platform an account. It comes with an API key, shown once, and the public keys your platform pins to check admissions.

02

A room for each sale

One call creates it: the capacity, when the queue and the sale open, how many shop at once. Sending it again is harmless, and a newer version replaces it.

03

Joins, after your checks

When a signed-in buyer asks to join, your platform calls QueueOps and hands the browser a visitor token. QueueOps gets your id for the person and a hash of their address, never the address or who they are.

04

The browser asks

It polls its status through your own domain, as often as it is told to, and receives its admission when its turn comes.

05

You check, locally

At checkout your platform verifies the token’s signature, room, person and expiry against the keys it pinned. It never asks QueueOps whether someone is admitted.

06

A key check

QueueOps says which key signs your admissions now, so your platform can confirm it has pinned that key before a key change could turn anyone away.

Where it stops

What it has not done yet, and what it will not do.

The queue engine, both tokens, the room API, signing-key rotation, the estimated wait and the metrics are built and tested, and so is the TicketOps side. What remains is a live sale, a load test on the real host, API key rotation, and something reading the metrics.

Not yet in front of a live sale

not yet shown

QueueOps and its TicketOps integration are built and tested end to end. The rehearsal and the first real room are still to come, so every figure on this page is from tests and a load test, not from a sale.

The throughput target is not shown on the real host

not yet shown

The plan asks for 10,000 polls a second across three replicas. The load test ran on a busy laptop and did not reach it; a run on the production host with nothing else running is still to do.

Private, and accounts are made by hand

access

The source is private and there is no sign-up. An operator makes each platform’s account and hands over its key, which is how we would set yours up.

One Redis, and it fails closed

by design

Every room lives in one Redis that writes each join to disk before answering. While it is unreachable, joins and polls are refused with a 503; buyers already admitted keep buying, because the platform checks their tokens itself.

A place is never given back

by design

Everyone who joins counts against the capacity for good. When more people want in than there is room for, arrival decides who gets a place at all, and the shuffle orders only those who did. An admission that runs out is final.

No API key rotation yet

roadmap

Signing keys rotate in stages without downtime, but a platform’s API key does not: replacing a leaked one means a new account, between sales.

Metrics with nothing reading them

roadmap

Each replica serves its counters in Prometheus format and logs them once a minute, warning when the ticker runs late or Redis fills. Nothing scrapes them yet.

Behind the project

Built by Eight Mile in London, as part of our software development work: the same engineers who build and run systems like it for clients.

Next step

Running on-sales that sell out in minutes?

QueueOps is ours, and it stays private. We run it as a service: your platform gets an account, opens a room for each sale and checks admissions itself, with no call back at checkout. TicketOps, the stadium ticketing platform we build, is the first one integrated with it. Tell us about your on-sales and we will tell you plainly whether it fits.

Meet the engineers who would do the work