Skip to content

Commit

Permalink
Merge pull request #1 from rtckit/v2.0.0
Browse files Browse the repository at this point in the history
v2.0.0
  • Loading branch information
cdosoftei authored Aug 17, 2021
2 parents ab552a2 + 98b28a9 commit de05494
Show file tree
Hide file tree
Showing 12 changed files with 52 additions and 68 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.editorconfig
.phpunit.result.cache
reports
vendor
Expand Down
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ before_script:
- echo "xdebug.mode=coverage" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini

script:
- php -d memory_limit=-1 ./vendor/bin/phpstan analyse -n -vvv --ansi --level=max src
- php -d memory_limit=-1 ./vendor/bin/psalm --show-info=true
- php -d memory_limit=-1 ./vendor/bin/phpunit --coverage-text --coverage-clover build/logs/clover.xml
- php -d memory_limit=-1 ./vendor/bin/phpstan analyse -c ./etc/phpstan.neon -n -vvv --ansi --level=max src
- php -d memory_limit=-1 ./vendor/bin/psalm --config=./etc/psalm.xml --show-info=true
- php -d memory_limit=-1 ./vendor/bin/phpunit -c ./etc/phpunit.xml.dist --coverage-text --coverage-clover build/logs/clover.xml
- if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT; fi
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,15 @@ Asynchronous [Redlock](https://redis.io/topics/distlock) algorithm implementatio

## Quickstart

Once [installed](#installation), you can incorporate Redlock in your projects by instantiating its _Custodian_; this entity is responsible for lock orchestration and it requires access to your process's event loop as well as to a Redis client object instance, e.g.
Once [installed](#installation), you can incorporate Redlock in your projects by instantiating its _Custodian_; this entity is responsible for lock orchestration and it requires access to a Redis client object instance, e.g.

```php
/* Instantiate prerequisites */
$loop = \React\EventLoop\Factory::create();
$factory = new \Clue\React\Redis\Factory($loop);
$factory = new \Clue\React\Redis\Factory(\React\EventLoop\Loop::get());
$client = $factory->createLazyClient('127.0.0.1');

/* Instantiate our lock custodian */
$custodian = new \RTCKit\React\Redlock\Custodian($loop, $client);
$custodian = new \RTCKit\React\Redlock\Custodian($client);
```

#### Acquiring locks
Expand Down Expand Up @@ -106,16 +105,16 @@ composer install
Then, go to the project root and run:

```bash
php -d memory_limit=-1 ./vendor/bin/phpunit
php -d memory_limit=-1 ./vendor/bin/phpunit -c ./etc/phpunit.xml.dist
```

### Static Analysis

In order to ensure high code quality, Redlock uses [PHPStan](https://github.com/phpstan/phpstan) and [Psalm](https://github.com/vimeo/psalm):

```sh
php -d memory_limit=-1 ./vendor/bin/phpstan analyse -n -vvv --ansi --level=max src
php -d memory_limit=-1 ./vendor/bin/psalm --show-info=true
php -d memory_limit=-1 ./vendor/bin/phpstan analyse -c ./etc/phpstan.neon -n -vvv --ansi --level=max src
php -d memory_limit=-1 ./vendor/bin/psalm --config=./etc/psalm.xml --show-info=true
```

## License
Expand Down
9 changes: 5 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "rtckit/react-redlock",
"description": "Asynchronous distributed locks with Redis and ReactPHP",
"version": "1.0.0",
"version": "2.0.0",
"type": "library",
"keywords": [
"lock",
Expand All @@ -24,12 +24,13 @@
},
"require": {
"php": ">=7.2",
"clue/redis-react": "^2.0"
"clue/redis-react": "^2.4",
"react/event-loop": "^1.2"
},
"require-dev": {
"phpstan/phpstan": "^0.12",
"phpunit/phpunit": "^9.4",
"vimeo/psalm": "^4.0"
"phpunit/phpunit": "^9.5",
"vimeo/psalm": "^4.9"
},
"autoload": {
"psr-4": {
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion phpstan.neon → etc/phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ parameters:
ignoreErrors:
- '#Call to an undefined method Clue\\React\\Redis\\Client::#'
includes:
- vendor/phpstan/phpstan/conf/bleedingEdge.neon
- ../vendor/phpstan/phpstan/conf/bleedingEdge.neon
6 changes: 3 additions & 3 deletions phpunit.xml.dist → etc/phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
<!-- PHPUnit configuration file with new format for PHPUnit 9.3+ -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
bootstrap="vendor/autoload.php"
bootstrap="../vendor/autoload.php"
colors="true"
cacheResult="false">
<testsuites>
<testsuite name="reactphp-redlock test suite">
<directory>./tests/</directory>
<directory>../tests/</directory>
</testsuite>
</testsuites>
<coverage>
<include>
<directory>./src/</directory>
<directory>../src/</directory>
</include>
</coverage>
</phpunit>
4 changes: 2 additions & 2 deletions psalm.xml → etc/psalm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="src" />
<directory name="../src" />
<ignoreFiles>
<directory name="vendor" />
<directory name="../vendor" />
</ignoreFiles>
</projectFiles>

Expand Down
15 changes: 6 additions & 9 deletions examples/01-basic.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
require(__DIR__ . '/../vendor/autoload.php');

use Clue\React\Redis\Factory as RedisFactory;
use React\EventLoop\Factory as LoopFactory;
use React\EventLoop\Loop;
use React\Promise\PromiseInterface;
use RTCKit\React\Redlock\Custodian;
use RTCKit\React\Redlock\Lock;
Expand All @@ -23,14 +23,13 @@
}

/* Instantiate prerequisites */
$loop = LoopFactory::create();
$factory = new RedisFactory($loop);
$factory = new RedisFactory(Loop::get());
$client = $factory->createLazyClient($host);

/* Instantiate our lock custodian */
$custodian = new Custodian($loop, $client);
$custodian = new Custodian($client);

$loop->addTimer(0.001, function () use ($custodian, $loop): void {
Loop::addTimer(0.001, function () use ($custodian): void {
$custodian->acquire('01-basic', 1)
->then(function (?Lock $lock) use ($custodian): PromiseInterface {
if (is_null($lock)) {
Expand Down Expand Up @@ -58,11 +57,9 @@
->otherwise(function (Throwable $t): void {
echo "Something bad happened:" . PHP_EOL . " > " . $t->getMessage() . PHP_EOL;
})
->always(function() use ($loop): void {
$loop->stop();
->always(function(): void {
Loop::stop();

echo "Bye!" . PHP_EOL;
});
});

$loop->run();
17 changes: 7 additions & 10 deletions examples/02-spin.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
require(__DIR__ . '/../vendor/autoload.php');

use Clue\React\Redis\Factory as RedisFactory;
use React\EventLoop\Factory as LoopFactory;
use React\EventLoop\Loop;
use React\Promise\PromiseInterface;
use RTCKit\React\Redlock\Custodian;
use RTCKit\React\Redlock\Lock;
Expand All @@ -22,15 +22,14 @@
}

/* Instantiate prerequisites */
$loop = LoopFactory::create();
$factory = new RedisFactory($loop);
$factory = new RedisFactory(Loop::get());
$client = $factory->createLazyClient($host);

/* Instantiate our lock custodian */
$custodian = new Custodian($loop, $client);
$custodian = new Custodian($client);

/* First routine to acquire the lock */
$loop->addTimer(0.001, function () use ($custodian): void {
Loop::addTimer(0.001, function () use ($custodian): void {
/* Lock '02-spin' for 5 seconds */
$custodian->acquire('02-spin', 5)
->then(function (?Lock $lock): void {
Expand All @@ -46,7 +45,7 @@
});

/* Hopeful routine, attempting to eventually acquire the lock */
$loop->addTimer(1, function ($timer) use ($custodian, $loop): void {
Loop::addTimer(1, function ($timer) use ($custodian): void {
/* Attempt to lock '02-spin', trying up to 7 times with a one second pause between retries.
Once secured, hold the lock for 10 seconds. */
$custodian->spin(7, 1, '02-spin', 10)
Expand All @@ -60,11 +59,9 @@
->otherwise(function (Throwable $t): void {
echo "[hopeful] Something bad happened:" . PHP_EOL . " > " . $t->getMessage() . PHP_EOL;
})
->always(function() use ($loop): void {
$loop->stop();
->always(function(): void {
Loop::stop();

echo "Bye!" . PHP_EOL;
});
});

$loop->run();
11 changes: 3 additions & 8 deletions src/Custodian.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace RTCKit\React\Redlock;

use Clue\React\Redis\Client;
use React\EventLoop\LoopInterface;
use React\EventLoop\Loop;
use React\Promise\Deferred;
use React\Promise\PromiseInterface;
use function bin2hex;
Expand All @@ -23,21 +23,16 @@ final class Custodian
end
EOD;

/** @var LoopInterface Event loop we're bound to */
private $loop;

/** @var Client ReactPHP Redis client */
private $client;

/**
* Custodian constructor
*
* @param LoopInterface $loop Event loop we're bound to
* @param Client $client ReactPHP Redis client
*/
public function __construct(LoopInterface $loop, Client $client)
public function __construct(Client $client)
{
$this->loop = $loop;
$this->client = $client;
}

Expand Down Expand Up @@ -91,7 +86,7 @@ public function spin(int $attempts, float $interval, string $resource, float $tt
if (!is_null($lock)) {
$deferred->resolve($lock);
} else {
$this->loop->addTimer($interval, function () use ($deferred, $attempts, $interval, $resource, $ttl, $token) {
Loop::addTimer($interval, function () use ($deferred, $attempts, $interval, $resource, $ttl, $token) {
$deferred->resolve($this->spin(--$attempts, $interval, $resource, $ttl, $token));
});
}
Expand Down
36 changes: 15 additions & 21 deletions tests/CustodianTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace RTCKit\React\Redlock;

use PHPUnit\Framework\TestCase;
use React\EventLoop\Factory;
use React\EventLoop\Loop;
use React\Promise\PromiseInterface;
use function React\Promise\resolve;

Expand All @@ -14,21 +14,19 @@
*/
class CustodianTest extends TestCase
{
private $loop;
private $client;

/**
* @before
*/
public function setUpFactory()
{
$this->loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock();
$this->client = $this->getMockBuilder('Clue\React\Redis\Client')->getMock();
}

public function testConstructor()
{
$custodian = new Custodian($this->loop, $this->client);
$custodian = new Custodian($this->client);

$this->assertNotNull($custodian);
$this->assertInstanceOf(Custodian::class, $custodian);
Expand All @@ -41,7 +39,7 @@ public function testSuccessfulAcquire()
->with('set', ['resource', 'r4nd0m', 'NX', 'PX', 60000])
->willReturn(resolve('OK'));

$custodian = new Custodian($this->loop, $this->client);
$custodian = new Custodian($this->client);

$promise = $custodian->acquire('resource', 60, 'r4nd0m');

Expand All @@ -64,7 +62,7 @@ public function testFailedAcquire()
->with('set', ['2fail', 'r4nd0m', 'NX', 'PX', 60000])
->willReturn(resolve(null));

$custodian = new Custodian($this->loop, $this->client);
$custodian = new Custodian($this->client);

$promise = $custodian->acquire('2fail', 60, 'r4nd0m');

Expand All @@ -82,7 +80,7 @@ public function testAcquireOptionalToken()
->method('__call')
->willReturn(resolve('OK'));

$custodian = new Custodian($this->loop, $this->client);
$custodian = new Custodian($this->client);

$promise = $custodian->acquire('resource', 60);

Expand All @@ -100,8 +98,6 @@ public function testAcquireOptionalToken()

public function testSuccessfulSpin()
{
$loop = Factory::create();

$this->client->expects($this->exactly(5))
->method('__call')
->with('set', ['resource', 'r4nd0m', 'NX', 'PX', 60000])
Expand All @@ -113,30 +109,28 @@ public function testSuccessfulSpin()
resolve('OK')
);

$custodian = new Custodian($loop, $this->client);
$custodian = new Custodian($this->client);

$promise = $custodian->spin(5, 0.000001, 'resource', 60, 'r4nd0m');

$this->assertNotNull($promise);
$this->assertInstanceOf(PromiseInterface::class, $promise);

$promise->then(function (?Lock $lock) use ($loop) {
$promise->then(function (?Lock $lock) {
$this->assertNotNull($lock);
$this->assertInstanceOf(Lock::class, $lock);
$this->assertEquals('resource', $lock->getResource());
$this->assertEquals(60, $lock->getTTL());
$this->assertEquals('r4nd0m', $lock->getToken());

$loop->stop();
Loop::stop();
});

$loop->run();
Loop::run();
}

public function testFailedSpin()
{
$loop = Factory::create();

$this->client->expects($this->exactly(5))
->method('__call')
->with('set', ['resource', 'r4nd0m', 'NX', 'PX', 60000])
Expand All @@ -148,20 +142,20 @@ public function testFailedSpin()
resolve(null)
);

$custodian = new Custodian($loop, $this->client);
$custodian = new Custodian($this->client);

$promise = $custodian->spin(5, 0.000001, 'resource', 60, 'r4nd0m');

$this->assertNotNull($promise);
$this->assertInstanceOf(PromiseInterface::class, $promise);

$promise->then(function (?Lock $lock) use ($loop) {
$promise->then(function (?Lock $lock) {
$this->assertNull($lock);

$loop->stop();
Loop::stop();
});

$loop->run();
Loop::run();
}

public function testSuccessfulRelease()
Expand All @@ -172,7 +166,7 @@ public function testSuccessfulRelease()
->willReturn(resolve('1'));

$lock = new Lock('release', 60, 'r4nd0m');
$custodian = new Custodian($this->loop, $this->client);
$custodian = new Custodian($this->client);

$promise = $custodian->release($lock);

Expand All @@ -192,7 +186,7 @@ public function testFailedRelease()
->willReturn(resolve('0'));

$lock = new Lock('release', 60, 'r4nd0m');
$custodian = new Custodian($this->loop, $this->client);
$custodian = new Custodian($this->client);

$promise = $custodian->release($lock);

Expand Down

0 comments on commit de05494

Please sign in to comment.