Skip to content

Commit 94c240d

Browse files
Merge pull request #23 from utopia-php/redis-cluster
feat: add redis cluster adapter
2 parents 9175652 + 575491c commit 94c240d

File tree

6 files changed

+279
-5
lines changed

6 files changed

+279
-5
lines changed

docker-compose.yml

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ services:
88
- ./:/usr/local/src
99
depends_on:
1010
- redis
11+
- redis-cluster-0
1112
- swoole
1213
- workerman
1314

@@ -20,6 +21,15 @@ services:
2021
depends_on:
2122
- redis
2223

24+
swoole-redis-cluster:
25+
container_name: swoole-redis-cluster
26+
build: ./tests/Queue/servers/SwooleRedisCluster/.
27+
command: php /usr/src/code/tests/Queue/servers/SwooleRedisCluster/worker.php
28+
volumes:
29+
- ./:/usr/src/code
30+
depends_on:
31+
- redis-cluster-0
32+
2333
workerman:
2434
container_name: workerman
2535
build: ./tests/Queue/servers/Workerman/.
@@ -33,4 +43,38 @@ services:
3343
container_name: redis
3444
image: "redis:alpine"
3545
ports:
36-
- "6379:6379"
46+
- "6379:6379"
47+
48+
redis-cluster-0:
49+
image: docker.io/bitnami/redis-cluster:7.4
50+
environment:
51+
- ALLOW_EMPTY_PASSWORD=yes
52+
- REDIS_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
53+
- REDIS_NODES=redis-cluster-0 redis-cluster-1 redis-cluster-2 redis-cluster-3
54+
- REDIS_CLUSTER_CREATOR=yes
55+
- REDIS_CLUSTER_REPLICAS=0
56+
depends_on:
57+
- redis-cluster-1
58+
- redis-cluster-2
59+
- redis-cluster-3
60+
61+
redis-cluster-1:
62+
image: docker.io/bitnami/redis-cluster:7.4
63+
environment:
64+
- ALLOW_EMPTY_PASSWORD=yes
65+
- REDIS_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
66+
- REDIS_NODES=redis-cluster-0 redis-cluster-1 redis-cluster-2 redis-cluster-3
67+
68+
redis-cluster-2:
69+
image: docker.io/bitnami/redis-cluster:7.4
70+
environment:
71+
- ALLOW_EMPTY_PASSWORD=yes
72+
- REDIS_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
73+
- REDIS_NODES=redis-cluster-0 redis-cluster-1 redis-cluster-2 redis-cluster-3
74+
75+
redis-cluster-3:
76+
image: docker.io/bitnami/redis-cluster:7.4
77+
environment:
78+
- ALLOW_EMPTY_PASSWORD=yes
79+
- REDIS_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
80+
- REDIS_NODES=redis-cluster-0 redis-cluster-1 redis-cluster-2 redis-cluster-3
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
<?php
2+
3+
namespace Utopia\Queue\Connection;
4+
5+
use Utopia\Queue\Connection;
6+
7+
class RedisCluster implements Connection
8+
{
9+
10+
protected array $seeds;
11+
protected ?\RedisCluster $redis = null;
12+
13+
public function __construct(array $seeds)
14+
{
15+
$this->seeds = $seeds;
16+
}
17+
18+
public function rightPopLeftPushArray(string $queue, string $destination, int $timeout): array|false
19+
{
20+
$response = $this->rightPopLeftPush($queue, $destination, $timeout);
21+
22+
if (!$response) {
23+
return false;
24+
}
25+
26+
return json_decode($response, true);
27+
}
28+
public function rightPopLeftPush(string $queue, string $destination, int $timeout): string|false
29+
{
30+
$response = $this->getRedis()->bRPopLPush($queue, $destination, $timeout);
31+
32+
if (!$response) {
33+
return false;
34+
}
35+
36+
return $response;
37+
}
38+
public function rightPushArray(string $queue, array $value): bool
39+
{
40+
return !!$this->getRedis()->rPush($queue, json_encode($value));
41+
}
42+
43+
public function rightPush(string $queue, string $value): bool
44+
{
45+
return !!$this->getRedis()->rPush($queue, $value);
46+
}
47+
48+
public function leftPushArray(string $queue, array $value): bool
49+
{
50+
return !!$this->getRedis()->lPush($queue, json_encode($value));
51+
}
52+
53+
public function leftPush(string $queue, string $value): bool
54+
{
55+
return !!$this->getRedis()->lPush($queue, $value);
56+
}
57+
58+
public function rightPopArray(string $queue, int $timeout): array|false
59+
{
60+
$response = $this->rightPop($queue, $timeout);
61+
62+
if ($response === false) {
63+
return false;
64+
}
65+
66+
return json_decode($response, true) ?? false;
67+
}
68+
69+
public function rightPop(string $queue, int $timeout): string|false
70+
{
71+
$response = $this->getRedis()->brPop([$queue], $timeout);
72+
73+
if (empty($response)) {
74+
return false;
75+
}
76+
77+
return $response[1];
78+
}
79+
80+
public function leftPopArray(string $queue, int $timeout): array|false
81+
{
82+
$response = $this->getRedis()->blPop($queue, $timeout);
83+
84+
if (empty($response)) {
85+
return false;
86+
}
87+
88+
return json_decode($response[1], true) ?? false;
89+
}
90+
91+
public function leftPop(string $queue, int $timeout): string|false
92+
{
93+
$response = $this->getRedis()->blPop($queue, $timeout);
94+
95+
if (empty($response)) {
96+
return false;
97+
}
98+
99+
return $response[1];
100+
}
101+
102+
public function listRemove(string $queue, string $key): bool
103+
{
104+
return !!$this->getRedis()->lRem($queue, $key, 1);
105+
}
106+
107+
public function remove(string $key): bool
108+
{
109+
return !!$this->getRedis()->del($key);
110+
}
111+
112+
public function move(string $queue, string $destination): bool
113+
{
114+
return $this->getRedis()->move($queue, $destination);
115+
}
116+
117+
public function setArray(string $key, array $value): bool
118+
{
119+
return $this->set($key, json_encode($value));
120+
}
121+
122+
public function set(string $key, string $value): bool
123+
{
124+
return $this->getRedis()->set($key, $value);
125+
}
126+
127+
public function get(string $key): array|string|null
128+
{
129+
return $this->getRedis()->get($key);
130+
}
131+
132+
public function listSize(string $key): int
133+
{
134+
return $this->getRedis()->lLen($key);
135+
}
136+
137+
public function increment(string $key): int
138+
{
139+
return $this->getRedis()->incr($key);
140+
}
141+
142+
public function decrement(string $key): int
143+
{
144+
return $this->getRedis()->decr($key);
145+
}
146+
147+
public function listRange(string $key, int $total, int $offset): array
148+
{
149+
$start = $offset;
150+
$end = $start + $total - 1;
151+
$results = $this->getRedis()->lRange($key, $start, $end);
152+
153+
return $results;
154+
}
155+
156+
public function ping(): bool
157+
{
158+
try {
159+
foreach ($this->getRedis()->_masters() as $master) {
160+
$this->getRedis()->ping($master);
161+
}
162+
163+
return true;
164+
} catch (Exception $e) {
165+
return false;
166+
}
167+
}
168+
169+
protected function getRedis(): \RedisCluster
170+
{
171+
if ($this->redis) {
172+
return $this->redis;
173+
}
174+
175+
$this->redis = new \RedisCluster(null, $this->seeds);
176+
return $this->redis;
177+
}
178+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace Queue\E2E\Adapter;
4+
5+
use Tests\E2E\Adapter\Base;
6+
use Utopia\Queue\Client;
7+
use Utopia\Queue\Connection\Redis;
8+
use Utopia\Queue\Connection\RedisCluster;
9+
10+
class SwooleRedisClusterTest extends Base
11+
{
12+
protected function getClient(): Client
13+
{
14+
$connection = new RedisCluster(['redis-cluster-0:6379', 'redis-cluster-1:6379', 'redis-cluster-2:6379']);
15+
$client = new Client('swoole-redis-cluster', $connection);
16+
17+
return $client;
18+
}
19+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM phpswoole/swoole:php8.1-alpine
2+
3+
RUN apk add autoconf build-base
4+
5+
RUN docker-php-ext-enable redis
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
require_once __DIR__ . '/../../../../vendor/autoload.php';
4+
require_once __DIR__ . '/../tests.php';
5+
6+
use Utopia\Queue;
7+
use Utopia\Queue\Message;
8+
9+
$connection = new Queue\Connection\RedisCluster(['redis-cluster-0:6379', 'redis-cluster-1:6379', 'redis-cluster-2:6379']);
10+
$adapter = new Queue\Adapter\Swoole($connection, 12, 'swoole-redis-cluster');
11+
$server = new Queue\Server($adapter);
12+
13+
$server->job()
14+
->inject('message')
15+
->action(function (Message $message) {
16+
handleRequest($message);
17+
});
18+
19+
$server
20+
->error()
21+
->inject('error')
22+
->action(function ($th) {
23+
echo $th->getMessage() . PHP_EOL;
24+
});
25+
26+
$server
27+
->workerStart()
28+
->action(function () {
29+
echo "Worker Started" . PHP_EOL;
30+
});
31+
32+
$server->start();

tests/Queue/servers/tests.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,6 @@ function handleRequest(Queue\Message $job): void
2222
case 'test_bool':
2323
assert(is_bool($value));
2424

25-
break;
26-
case 'test_bool':
27-
assert(is_null($value));
28-
2925
break;
3026
case 'test_array':
3127
assert(is_array($value));

0 commit comments

Comments
 (0)