You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+3-145Lines changed: 3 additions & 145 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -25,150 +25,8 @@ British-style queuing for your code and infrastructure. First come, first served
25
25
> [!CAUTION]
26
26
> **Very Early Work in Progress** - This library is under active development and not yet production-ready. APIs will change, many implementations are stubs and test coverage is incomplete. Use at your own risk, contributions welcome.
27
27
28
-
## The Core Idea
28
+
## Documentation
29
29
30
-
*Everything has a breaking point.* A database has connection limits. An API has rate limits. A checkout flow falls over if 50,000 people hit it at once.
31
-
An airlock sits in front of that thing and makes everyone wait their turn nicely.
30
+
Full documentation, guides and examples at **[clegginabox.github.io/airlock-php](https://clegginabox.github.io/airlock-php/)**.
32
31
33
-
Every Airlock is composed of:
34
-
- A Seal — how capacity is enforced (the velvet rope)
35
-
- An Admission Strategy — who gets in next (the queue itself)
36
-
- An optional Notifier — how waiters are told it’s their turn (the “your table is ready” buzzer)
37
-
38
-
Swap one piece, get a different system. Same interface, different behaviour. Dead simple.
39
-
40
-
## Best-Effort / Anti-Hug Gate
41
-
42
-
No fairness guarantees. First request to hit free capacity wins. If two requests arrive at the same time, one gets in and one doesn’t — and there’s no predicting which.
43
-
44
-
Fast, simple, resilient. Perfect for protecting an endpoint from the hug of death when you don’t care who gets through, just how many.
45
-
46
-
```php
47
-
use Clegginabox\Airlock\Bridge\Symfony\Seal\SymfonySemaphoreSeal;use Clegginabox\Airlock\OpportunisticAirlock;use Symfony\Component\Semaphore\SemaphoreFactory;use Symfony\Component\Semaphore\Store\RedisStore;
48
-
49
-
$redis = new Redis();
50
-
$redis->connect('127.0.0.1');
51
-
52
-
// Allow up to N concurrent “expensive” requests.
53
-
$seal = new SymfonySemaphoreSeal(
54
-
factory: new SemaphoreFactory(new RedisStore($redis)),
55
-
resource: 'site_capacity',
56
-
limit: 20,
57
-
ttlInSeconds: 30,
58
-
autoRelease: false,
59
-
);
60
-
61
-
$airlock = new OpportunisticAirlock($seal);
62
-
63
-
$result = $airlock->enter($clientId);
64
-
```
65
-
66
-
## Strict Fairness (FIFO)
67
-
68
-
The proper British queue. Exact arrival order. Deterministic. No cutting, no exceptions.
69
-
70
-
If someone in front of you wanders off to browse the shop, the whole queue waits. Dead heads must be handled explicitly — the system won’t assume they’ve left just because they’ve gone quiet.
71
-
72
-
```php
73
-
use Clegginabox\Airlock\QueueAirlock;
74
-
use Clegginabox\Airlock\Queue\RedisFifoQueue;
75
-
76
-
$seal = new SemaphoreSeal(... limit: 50);
77
-
$queue = new RedisFifoQueue($redis);
78
-
79
-
$airlock = new QueueAirlock($seal, $queue);
80
-
81
-
$result = $airlock->enter($userId);
82
-
```
83
-
84
-
## Lottery (Fast, Unfair)
85
-
86
-
No ordering. High throughput. Self-healing under disconnects.
87
-
88
-
The Ryanair boarding approach. Priority boarding means nowt when everyone’s already elbowing toward the gate. If someone disconnects, they simply drop out of the draw — no cleanup required.
89
-
90
-
```php
91
-
use Clegginabox\Airlock\QueueAirlock;
92
-
use Clegginabox\Airlock\Queue\RedisLotteryQueue;
93
-
94
-
$seal = new SemaphoreSeal(... limit: 50);
95
-
$queue = new RedisLotteryQueue($redis);
96
-
97
-
$airlock = new QueueAirlock($seal, $queue);
98
-
```
99
-
100
-
## Aging Lottery (Fair-ish)
101
-
102
-
Same as the lottery, but the longer you wait, the better your odds. Eventually even the unluckiest punter gets through.
103
-
104
-
The “I’ve been waiting ages, surely it’s my turn” system. Not strictly fair, but feels fairer — and sometimes that’s what matters.
105
-
106
-
```php
107
-
use Clegginabox\Airlock\QueueAirlock;
108
-
use Clegginabox\Airlock\Queue\RedisLotteryQueue;
109
-
110
-
$seal = new SemaphoreSeal(... limit: 50);
111
-
$queue = new RedisAgingLotteryQueue($redis);
112
-
113
-
$airlock = new QueueAirlock($seal, $queue);
114
-
```
115
-
116
-
## Priority Queue (Logged-in Users First)
117
-
118
-
Higher priority users jump ahead. FIFO within the same tier. Guests wait, members skip the line.
119
-
120
-
The members’ entrance at the club. You’re still queuing, just… better.
121
-
122
-
```php
123
-
use Clegginabox\Airlock\QueueAirlock;
124
-
use Clegginabox\Airlock\Queue\PriorityQueue;
125
-
126
-
$seal = new SemaphoreSeal(... limit: 50);
127
-
$queue = new PriorityQueue($redis);
128
-
129
-
$airlock = new QueueAirlock($seal, $queue);
130
-
131
-
// Priority: higher = better. Logged-in users get priority 10, guests get 0.
132
-
$priority = $user->isLoggedIn() ? 10 : 0;
133
-
134
-
$result = $airlock->enter($userId, $priority);
135
-
```
136
-
137
-
Tiered priorities work too - VIPs at 100, paid members at 50, free users at 10, anonymous at 0.
138
-
139
-
## Singleton / Idempotency
140
-
141
-
Exactly one at a time. No queue, no waiting room UI — just a simple “is someone already doing this?” check.
142
-
143
-
Perfect for cron jobs that must never overlap, or user actions that shouldn’t fire twice if they double-click. The “we’re not having two of those” approach.
144
-
145
-
```php
146
-
use Clegginabox\Airlock\Bridge\Symfony\Seal\SymfonyLockSeal;use Clegginabox\Airlock\OpportunisticAirlock;
147
-
148
-
$seal = new SymfonyLockSeal();
149
-
$airlock = new OpportunisticAirlock($seal);
150
-
151
-
$airlock->withAdmitted('job:invoice', function () {
152
-
// guaranteed single-flight
153
-
});
154
-
```
155
-
156
-
## When Not to Use Airlock
157
-
158
-
Airlock is not trying to be Cloudflare. If you’re selling Glastonbury tickets to the entire country at once, you need infrastructure with a budget bigger than this library’s test coverage.
159
-
160
-
Airlock is for the stuff in between. The internal dashboard that falls over when someone sends a company-wide email. The checkout flow that can’t handle a flash sale. The webhook endpoint that your biggest customer keeps hammering.
161
-
162
-
It’s probably not the right fit if:
163
-
-**You just want to return 429s** — A rate limiter is simpler. Airlock assumes callers are willing to wait their turn.
164
-
-**Waiting is not an option** — If requests must fail immediately, you want fail-fast guards, not admission control.
0 commit comments