Skip to content

Commit 92cd0e2

Browse files
authored
Parallel running add support for related users (#26)
1 parent d9dda0c commit 92cd0e2

31 files changed

+807
-24
lines changed
File renamed without changes.

.github/workflows/test-php-80.yml

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Tests
2+
on: [push, pull_request]
3+
jobs:
4+
abrouter-tests-php-80:
5+
runs-on: ubuntu-latest
6+
strategy:
7+
matrix:
8+
operating-system: ['ubuntu-latest']
9+
php-versions: ['8.0']
10+
phpunit-versions: ['latest']
11+
include:
12+
- operating-system: 'ubuntu-latest'
13+
php-versions: '8.0'
14+
env:
15+
REDIS_HOST: 127.0.0.1
16+
steps:
17+
- uses: actions/checkout@v2
18+
- uses: nanasess/setup-php@master
19+
with:
20+
php-version: '8.0'
21+
- name: Update Composer
22+
run: sudo composer self-update 1.10.15 --no-interaction
23+
- name: Run Composer Install
24+
run: composer install --no-interaction
25+
- name: Start Redis
26+
uses: supercharge/redis-github-action@1.4.0
27+
with:
28+
redis-version: 6
29+
redis-container-name: redis
30+
- name: run tests
31+
run: vendor/bin/phpunit

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
"guzzlehttp/guzzle": "^6.5 || ^7.0",
2020
"ext-json": "*",
2121
"art4/json-api-client": "^1.0",
22-
"predis/predis": "^1.0 || ^2.0"
22+
"predis/predis": "^1.0 || ^2.0",
23+
"abrouter/related-users": "^0.0.1"
2324
},
2425
"require-dev": {
2526
"phpunit/phpunit": "^9",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Abrouter\Client\DB\Dictionary;
6+
7+
class ParallelRunningDictionary
8+
{
9+
public const IS_INITIAZLIED_KEY = 'parallelRunningIsInitialized';
10+
public const IS_RUNNING_KEY = 'parallelRunningReadyToServe';
11+
12+
public const IS_INITIAZLIED_TRUE_VALUE = 'initialized';
13+
public const IS_RUNNING_VALUE_TRUE = 'ready';
14+
public const IS_RUNNING_VALUE_STOPPED = 'stopped';
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Abrouter\Client\DB\Managers;
6+
7+
use Abrouter\Client\DB\Dictionary\ParallelRunningDictionary;
8+
use Abrouter\Client\DB\RedisConnection;
9+
use Abrouter\Client\DB\Repositories\ParallelRunningStateCachedRepository;
10+
11+
class ParallelRunningStateManager
12+
{
13+
private RedisConnection $redisConnection;
14+
15+
private ParallelRunningStateCachedRepository $parallelRunningStateCachedRepository;
16+
17+
public function __construct(
18+
RedisConnection $redisConnection,
19+
ParallelRunningStateCachedRepository $parallelRunningStateCachedRepository
20+
) {
21+
$this->redisConnection = $redisConnection;
22+
$this->parallelRunningStateCachedRepository = $parallelRunningStateCachedRepository;
23+
}
24+
25+
public function setReadyToServe()
26+
{
27+
$this->redisConnection->getConnection()->set(
28+
ParallelRunningDictionary::IS_RUNNING_KEY,
29+
ParallelRunningDictionary::IS_RUNNING_VALUE_TRUE
30+
);
31+
$this->parallelRunningStateCachedRepository->clearCacheServing();
32+
}
33+
34+
public function setStopServing()
35+
{
36+
$this->redisConnection->getConnection()->set(
37+
ParallelRunningDictionary::IS_RUNNING_KEY,
38+
ParallelRunningDictionary::IS_RUNNING_VALUE_STOPPED
39+
);
40+
$this->parallelRunningStateCachedRepository->clearCacheServing();
41+
}
42+
43+
public function setInitialized()
44+
{
45+
$this->redisConnection->getConnection()->set(
46+
ParallelRunningDictionary::IS_INITIAZLIED_KEY,
47+
ParallelRunningDictionary::IS_INITIAZLIED_TRUE_VALUE
48+
);
49+
$this->parallelRunningStateCachedRepository->clearCacheInitialized();
50+
}
51+
}

src/DB/RelatedUsersStore.php

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Abrouter\Client\DB;
6+
7+
use Abrouter\Client\Exceptions\RelatedUsersStoreLoadException;
8+
use Abrouter\RelatedUsers\Collections\RelatedUsersCollection;
9+
10+
class RelatedUsersStore
11+
{
12+
private static ?RelatedUsersCollection $store = null;
13+
14+
/**
15+
* @throws RelatedUsersStoreLoadException
16+
*/
17+
public function get(): RelatedUsersCollection
18+
{
19+
if (self::$store !== null) {
20+
return self::$store;
21+
}
22+
23+
throw new RelatedUsersStoreLoadException('Related users store should be initialized');
24+
}
25+
26+
public static function load(array $relatedUsersList): void
27+
{
28+
self::$store = new RelatedUsersCollection($relatedUsersList);
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Abrouter\Client\DB\Repositories;
6+
7+
use Abrouter\Client\DB\Dictionary\ParallelRunningDictionary;
8+
use Abrouter\Client\DB\RunTimeCache;
9+
10+
class ParallelRunningStateCachedRepository
11+
{
12+
private ParallelRunningStateRepository $parallelRunningStateRepository;
13+
14+
public function __construct(ParallelRunningStateRepository $parallelRunningStateRepository)
15+
{
16+
$this->parallelRunningStateRepository = $parallelRunningStateRepository;
17+
}
18+
19+
public function isReady(): bool
20+
{
21+
$cached = RunTimeCache::get(ParallelRunningDictionary::IS_RUNNING_KEY);
22+
if ($cached !== null) {
23+
return $cached === 'true';
24+
}
25+
26+
$isReady = $this->parallelRunningStateRepository->isReady();
27+
RunTimeCache::set(
28+
ParallelRunningDictionary::IS_RUNNING_KEY,
29+
$isReady ? 'true' : 'false'
30+
);
31+
32+
return $isReady;
33+
}
34+
35+
public function isInitialized()
36+
{
37+
$cached = RunTimeCache::get(ParallelRunningDictionary::IS_INITIAZLIED_KEY);
38+
if ($cached !== null) {
39+
return $cached === 'true';
40+
}
41+
42+
$value = $this->parallelRunningStateRepository->isInitialized();
43+
RunTimeCache::set(
44+
ParallelRunningDictionary::IS_INITIAZLIED_KEY,
45+
$value ? 'true' : 'false'
46+
);
47+
48+
return $value;
49+
}
50+
51+
public function clearCacheInitialized()
52+
{
53+
RunTimeCache::removeIfExists(ParallelRunningDictionary::IS_INITIAZLIED_KEY);
54+
}
55+
56+
public function clearCacheServing()
57+
{
58+
RunTimeCache::removeIfExists(ParallelRunningDictionary::IS_RUNNING_KEY);
59+
}
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Abrouter\Client\DB\Repositories;
6+
7+
use Abrouter\Client\DB\Dictionary\ParallelRunningDictionary;
8+
use Abrouter\Client\DB\RedisConnection;
9+
10+
class ParallelRunningStateRepository
11+
{
12+
private RedisConnection $redisConnection;
13+
14+
public function __construct(RedisConnection $redisConnection)
15+
{
16+
$this->redisConnection = $redisConnection;
17+
}
18+
19+
public function isInitialized(): bool
20+
{
21+
$value = $this->redisConnection->getConnection()->get(ParallelRunningDictionary::IS_INITIAZLIED_KEY);
22+
return $value === ParallelRunningDictionary::IS_INITIAZLIED_TRUE_VALUE;
23+
}
24+
25+
public function isReady(): bool
26+
{
27+
$value = $this->redisConnection->getConnection()->get(ParallelRunningDictionary::IS_RUNNING_KEY);
28+
return $value === ParallelRunningDictionary::IS_RUNNING_VALUE_TRUE;
29+
}
30+
}

src/DB/RunTimeCache.php

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Abrouter\Client\DB;
6+
7+
class RunTimeCache
8+
{
9+
private static array $data = [];
10+
11+
public static function set(string $key, string $value): void
12+
{
13+
self::$data[$key] = $value;
14+
}
15+
16+
public static function removeIfExists(string $key): void
17+
{
18+
if (!isset(self::$data[$key])) {
19+
return ;
20+
}
21+
22+
unset(self::$data[$key]);
23+
}
24+
25+
26+
public static function get($key): ?string
27+
{
28+
return self::$data[$key] ?? null;
29+
}
30+
31+
public static function flushAll(): void
32+
{
33+
self::$data = [];
34+
}
35+
}

src/Events/EventDispatcher.php

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
use Abrouter\Client\Config\Accessors\ParallelRunConfigAccessor;
88
use Abrouter\Client\Contracts\TaskContract;
9-
use Abrouter\Client\Contracts\TaskManagerContract;
109

1110
class EventDispatcher
1211
{

src/Events/EventHandlersMap.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Abrouter\Client\Contracts\TaskContract;
88
use Abrouter\Client\Events\Handlers\AddUserToBranchHandler;
9+
use Abrouter\Client\Events\Handlers\RelatedUsersStatisticsInterceptor;
910
use Abrouter\Client\Events\Handlers\StatisticsSenderHandler;
1011
use Abrouter\Client\Services\ExperimentsParallelRun\AddUserToBranchTask;
1112
use Abrouter\Client\Services\Statistics\SendEventTask;
@@ -16,14 +17,18 @@ class EventHandlersMap
1617

1718
private StatisticsSenderHandler $statisticsSenderHandler;
1819

20+
private RelatedUsersStatisticsInterceptor $relatedUsersStatisticsInterceptor;
21+
1922
private array $map;
2023

2124
public function __construct(
2225
AddUserToBranchHandler $addUserToBranchHandler,
23-
StatisticsSenderHandler $statisticsSenderHandler
26+
StatisticsSenderHandler $statisticsSenderHandler,
27+
RelatedUsersStatisticsInterceptor $relatedUsersStatisticsInterceptor
2428
) {
2529
$this->addUserToBranchHandler = $addUserToBranchHandler;
2630
$this->statisticsSenderHandler = $statisticsSenderHandler;
31+
$this->relatedUsersStatisticsInterceptor = $relatedUsersStatisticsInterceptor;
2732
$this->map = $this->getInitialMap();
2833
}
2934

@@ -69,6 +74,7 @@ private function getInitialMap(): array
6974
],
7075
SendEventTask::class => [
7176
$this->statisticsSenderHandler,
77+
$this->relatedUsersStatisticsInterceptor,
7278
],
7379
];
7480
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Abrouter\Client\Events\Handlers;
6+
7+
use Abrouter\Client\Contracts\TaskContract;
8+
use Abrouter\Client\DB\RelatedUsersStore;
9+
use Abrouter\Client\Events\HandlerInterface;
10+
use Abrouter\Client\Services\ExperimentsParallelRun\ParallelRunSwitch;
11+
use Abrouter\Client\Services\Statistics\SendEventTask;
12+
13+
class RelatedUsersStatisticsInterceptor implements HandlerInterface
14+
{
15+
private ParallelRunSwitch $parallelRunSwitch;
16+
17+
private RelatedUsersStore $relatedUsersStore;
18+
19+
public function __construct(
20+
ParallelRunSwitch $parallelRunSwitch,
21+
RelatedUsersStore $relatedUsersStore
22+
) {
23+
$this->parallelRunSwitch = $parallelRunSwitch;
24+
$this->relatedUsersStore = $relatedUsersStore;
25+
}
26+
27+
public function handle(TaskContract $taskContract): bool
28+
{
29+
if (!$taskContract instanceof SendEventTask) {
30+
return false;
31+
}
32+
33+
if (!$this->parallelRunSwitch->isEnabled()) {
34+
return false;
35+
}
36+
37+
$userId = $taskContract->getEventDTO()->getBaseEventDTO()->getUserId();
38+
$temporaryUserId = $taskContract->getEventDTO()->getBaseEventDTO()->getTemporaryUserId();
39+
40+
$this->relatedUsersStore->get()->append($userId, $temporaryUserId);
41+
42+
return true;
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Abrouter\Client\Exceptions;
6+
7+
use Exception;
8+
9+
class RelatedUsersStoreLoadException extends Exception
10+
{
11+
}

src/RemoteEntity/Cache/Cacher.php

+12-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,12 @@ public function isEnabled(): bool
2121
return $this->kvStorageConfigAccessor->hasKvStorage();
2222
}
2323

24-
public function fetch(string $id, string $type, int $expireIn, callable $fetchFunction): ?object
25-
{
24+
public function fetch(
25+
string $id,
26+
string $type,
27+
int $expireIn,
28+
callable $fetchFunction
29+
): ?object {
2630
$objectId = $this->getObjectId($id, $type);
2731
$object = $this->kvStorageConfigAccessor->getKvStorage()->get($objectId);
2832
if ($object !== null) {
@@ -34,6 +38,12 @@ public function fetch(string $id, string $type, int $expireIn, callable $fetchFu
3438
return $object;
3539
}
3640

41+
public function get(string $id, string $type): object
42+
{
43+
$objectId = $this->getObjectId($id, $type);
44+
return unserialize($this->kvStorageConfigAccessor->getKvStorage()->get($objectId));
45+
}
46+
3747
private function getObjectId(string $id, string $type): string
3848
{
3949
return join('', [

0 commit comments

Comments
 (0)