Skip to content

Commit 7106f45

Browse files
committed
Seal interface WIP
1 parent ddaf028 commit 7106f45

23 files changed

+453
-10
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ WORKDIR /app
55
COPY --from=mlocati/php-extension-installer /usr/bin/install-php-extensions /usr/local/bin/
66

77
# Install PHP extensions
8-
RUN install-php-extensions redis
8+
RUN install-php-extensions redis memcached zookeeper

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
"require": {
2323
"php": "^8.4",
2424
"ext-redis": "*",
25+
"ext-memcached": "*",
26+
"ext-zookeeper": "*",
2527
"symfony/console": "^8.0",
2628
"symfony/lock": "^8.0",
2729
"symfony/semaphore": "^8.0"
@@ -37,6 +39,7 @@
3739
"rector/rector": "^2.3",
3840
"slevomat/coding-standard": "^8.26",
3941
"squizlabs/php_codesniffer": "^4.0",
42+
"symfony/amazon-dynamo-db-lock": "^8.0",
4043
"symfony/framework-bundle": "^8.0",
4144
"symfony/mercure": "^0.7.2",
4245
"symfony/rate-limiter": "^8.0",

src/Bridge/Laravel/Seal/LaravelRateLimiterSeal.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@
77
/**
88
* Wraps Illuminate\Cache\RateLimiter
99
*/
10-
class LaravelRateLimiterSeal {}
10+
class LaravelRateLimiterSeal
11+
{
12+
}

src/Bridge/Symfony/Seal/SymfonyRateLimiterSeal.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
declare(strict_types=1);
44

5-
65
namespace Clegginabox\Airlock\Bridge\Symfony\Seal;
76

8-
class SymfonyRateLimiterSeal {}
7+
class SymfonyRateLimiterSeal
8+
{
9+
}

src/Factory/LockFactory.php

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Clegginabox\Airlock\Factory;
6+
7+
use Clegginabox\Airlock\Seal\LocalLockSeal;
8+
use Clegginabox\Airlock\Seal\LockSeal;
9+
use Clegginabox\Airlock\Seal\RemoteLockSeal;
10+
use Memcached;
11+
use Redis;
12+
use Symfony\Component\Lock\Bridge\DynamoDb\Store\DynamoDbStore;
13+
use Symfony\Component\Lock\LockFactory as SymfonyLockFactory;
14+
use Symfony\Component\Lock\PersistingStoreInterface;
15+
use Symfony\Component\Lock\Store\DoctrineDbalPostgreSqlStore;
16+
use Symfony\Component\Lock\Store\DoctrineDbalStore;
17+
use Symfony\Component\Lock\Store\FlockStore;
18+
use Symfony\Component\Lock\Store\MemcachedStore;
19+
use Symfony\Component\Lock\Store\MongoDbStore;
20+
use Symfony\Component\Lock\Store\PdoStore;
21+
use Symfony\Component\Lock\Store\PostgreSqlStore;
22+
use Symfony\Component\Lock\Store\RedisStore;
23+
use Symfony\Component\Lock\Store\ZookeeperStore;
24+
use Zookeeper;
25+
26+
class LockFactory
27+
{
28+
public static function flock(?string $lockPath, string $resource, int $ttl, bool $autoRelease): LocalLockSeal
29+
{
30+
return new LocalLockSeal(
31+
factory: new SymfonyLockFactory(
32+
new FlockStore($lockPath ?? sys_get_temp_dir())
33+
),
34+
resource: $resource,
35+
ttlInSeconds: $ttl,
36+
autoRelease: $autoRelease
37+
);
38+
}
39+
40+
/**
41+
* @remote
42+
* @expiring
43+
*/
44+
public static function memcached(Memcached $memcached, string $resource, int $ttl, bool $autoRelease): RemoteLockSeal
45+
{
46+
return new RemoteLockSeal(
47+
factory: new SymfonyLockFactory(new MemcachedStore($memcached)),
48+
resource: $resource,
49+
ttlInSeconds: $ttl,
50+
autoRelease: $autoRelease
51+
);
52+
}
53+
54+
/**
55+
* @remote
56+
* @expiring
57+
*/
58+
public static function mongodb(string $dsn, array $options, string $resource, int $ttl, bool $autoRelease): LockSeal
59+
{
60+
return self::lockSeal(
61+
store: new MongoDbStore($dsn, $options),
62+
resource: $resource,
63+
ttl: $ttl,
64+
autoRelease: $autoRelease
65+
);
66+
}
67+
68+
/**
69+
* @remote
70+
* @expiring
71+
*/
72+
public static function pdo(string $dsn, array $options, string $resource, int $ttl, bool $autoRelease): LockSeal
73+
{
74+
return self::lockSeal(
75+
store: new PdoStore($dsn, $options),
76+
resource: $resource,
77+
ttl: $ttl,
78+
autoRelease: $autoRelease
79+
);
80+
}
81+
82+
public static function doctrineDbal(string $dsn, string $resource, int $ttl, bool $autoRelease): LockSeal
83+
{
84+
return self::lockSeal(
85+
store: new DoctrineDbalStore($dsn),
86+
resource: $resource,
87+
ttl: $ttl,
88+
autoRelease: $autoRelease
89+
);
90+
}
91+
92+
/**
93+
* @remote
94+
*/
95+
public static function postgresSql(string $dsn, string $resource, int $ttl, bool $autoRelease): LockSeal
96+
{
97+
return self::lockSeal(
98+
store: new PostgreSqlStore($dsn),
99+
resource: $resource,
100+
ttl: $ttl,
101+
autoRelease: $autoRelease
102+
);
103+
}
104+
105+
public static function doctrineDbalPostgresSql(string $dsn, string $resource, int $ttl, bool $autoRelease): LockSeal
106+
{
107+
return self::lockSeal(
108+
store: new DoctrineDbalPostgreSqlStore($dsn),
109+
resource: $resource,
110+
ttl: $ttl,
111+
autoRelease: $autoRelease
112+
);
113+
}
114+
115+
/**
116+
* @remote
117+
* @expiring
118+
*/
119+
public static function redis(Redis $redis, string $resource, int $ttl, bool $autoRelease): RemoteLockSeal
120+
{
121+
return new RemoteLockSeal(
122+
factory: new SymfonyLockFactory(new RedisStore($redis)),
123+
resource: $resource,
124+
ttlInSeconds: $ttl,
125+
autoRelease: $autoRelease
126+
);
127+
}
128+
129+
/**
130+
* @remote
131+
*/
132+
public static function zookeeper(Zookeeper $zookeeper, string $resource, int $ttl, bool $autoRelease): LockSeal
133+
{
134+
return self::lockSeal(
135+
store: new ZookeeperStore($zookeeper),
136+
resource: $resource,
137+
ttl: $ttl,
138+
autoRelease: $autoRelease
139+
);
140+
}
141+
142+
public static function dynamoDb(string $dsn, string $resource, int $ttl, bool $autoRelease): LockSeal
143+
{
144+
return self::lockSeal(
145+
store: new DynamoDbStore($dsn),
146+
resource: $resource,
147+
ttl: $ttl,
148+
autoRelease: $autoRelease
149+
);
150+
}
151+
152+
public static function combined()
153+
{
154+
// @todo
155+
}
156+
157+
private static function lockSeal(PersistingStoreInterface $store, string $resource, int $ttl, bool $autoRelease): LockSeal
158+
{
159+
return new LockSeal(
160+
factory: new SymfonyLockFactory($store),
161+
resource: $resource,
162+
ttlInSeconds: $ttl,
163+
autoRelease: $autoRelease
164+
);
165+
}
166+
167+
private static function localLockSeal(PersistingStoreInterface $store, string $resource, int $ttl, bool $autoRelease): LocalLockSeal
168+
{
169+
}
170+
}

src/HealthCheckerInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace Clegginabox\Airlock;
46

57
interface HealthCheckerInterface

src/Lock/LockFactoryInterface.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Clegginabox\Airlock\Lock;
6+
7+
use Symfony\Component\Lock\Key;
8+
9+
interface LockFactoryInterface
10+
{
11+
public function createLock(string $resource, ?float $ttl = 300.0, bool $autoRelease = true);
12+
13+
public function createLockFromKey(Key $key, ?float $ttl = 300.0, bool $autoRelease = true);
14+
}

src/Queue/BackpressureQueue.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ public function __construct(
111111
private QueueInterface $inner,
112112
private HealthCheckerInterface $healthChecker,
113113
private float $minHealthToAdmit = 0.2,
114-
) {}
114+
) {
115+
}
115116

116117
// Your implementation here
117118
public function add(string $identifier, int $priority = 0): int

src/Seal/BlockingSeal.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Clegginabox\Airlock\Seal;
6+
7+
/**
8+
* Marker interface for seals that support blocking acquisition.
9+
*
10+
* Implementations may wait until the seal becomes available
11+
* instead of failing immediately.
12+
*/
13+
interface BlockingSeal
14+
{
15+
}

src/Seal/CooldownSeal.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44

55
namespace Clegginabox\Airlock\Seal;
66

7-
class CooldownSeal
7+
class CooldownSeal implements RemoteSeal, NonReleasableSeal, RequiresTtl
88
{
99
}

0 commit comments

Comments
 (0)