Compare commits
No commits in common. "master" and "v1.0.2" have entirely different histories.
6 changed files with 3 additions and 219 deletions
|
@ -96,18 +96,4 @@ abstract class CommandMessage
|
||||||
|
|
||||||
return $options;
|
return $options;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* For lockable message
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function __serialize(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'commandName' => $this->getCommandName(),
|
|
||||||
'arguments' => $this->getArguments(),
|
|
||||||
'options' => $this->getOptions()
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace RetailCrm\ServiceBundle\Messenger\Middleware;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface LockableMessage
|
|
||||||
*
|
|
||||||
* @package RetailCrm\ServiceBundle\Messenger\Middleware
|
|
||||||
*/
|
|
||||||
interface LockableMessage
|
|
||||||
{
|
|
||||||
public function __serialize(): array;
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace RetailCrm\ServiceBundle\Messenger\Middleware;
|
|
||||||
|
|
||||||
use Symfony\Component\Lock\LockFactory;
|
|
||||||
use Symfony\Component\Messenger\Envelope;
|
|
||||||
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
|
|
||||||
use Symfony\Component\Messenger\Middleware\StackInterface;
|
|
||||||
use Symfony\Component\Messenger\Stamp\ReceivedStamp;
|
|
||||||
use Throwable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class LockableMessageMiddleware
|
|
||||||
*
|
|
||||||
* @package RetailCrm\ServiceBundle\Messenger\Middleware
|
|
||||||
*/
|
|
||||||
class LockableMessageMiddleware implements MiddlewareInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var LockFactory
|
|
||||||
*/
|
|
||||||
private $lockFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int|null
|
|
||||||
*/
|
|
||||||
private $ttl;
|
|
||||||
|
|
||||||
public function __construct(LockFactory $lockFactory, int $ttl = null)
|
|
||||||
{
|
|
||||||
$this->lockFactory = $lockFactory;
|
|
||||||
$this->ttl = $ttl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param Envelope $envelope
|
|
||||||
* @param StackInterface $stack
|
|
||||||
*
|
|
||||||
* @return Envelope
|
|
||||||
*
|
|
||||||
* @throws Throwable
|
|
||||||
*/
|
|
||||||
public function handle(Envelope $envelope, StackInterface $stack): Envelope
|
|
||||||
{
|
|
||||||
$message = $envelope->getMessage();
|
|
||||||
|
|
||||||
if ($envelope->all(ReceivedStamp::class) && $message instanceof LockableMessage) {
|
|
||||||
$lock = $this->lockFactory->createLock($this->objectHash($message), $this->ttl);
|
|
||||||
if (!$lock->acquire()) {
|
|
||||||
return $envelope;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return $stack->next()->handle($envelope, $stack);
|
|
||||||
} catch (Throwable $exception) {
|
|
||||||
throw $exception;
|
|
||||||
} finally {
|
|
||||||
$lock->release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $stack->next()->handle($envelope, $stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param LockableMessage $message
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
private function objectHash(LockableMessage $message): string
|
|
||||||
{
|
|
||||||
return hash('crc32', serialize($message));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,9 +3,8 @@
|
||||||
namespace RetailCrm\ServiceBundle\Tests\DataFixtures;
|
namespace RetailCrm\ServiceBundle\Tests\DataFixtures;
|
||||||
|
|
||||||
use RetailCrm\ServiceBundle\Messenger\CommandMessage;
|
use RetailCrm\ServiceBundle\Messenger\CommandMessage;
|
||||||
use RetailCrm\ServiceBundle\Messenger\Middleware\LockableMessage;
|
|
||||||
|
|
||||||
class TestMessage extends CommandMessage implements LockableMessage
|
class TestMessage extends CommandMessage
|
||||||
{
|
{
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,113 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace RetailCrm\ServiceBundle\Tests\Messenger\Middleware;
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use RetailCrm\ServiceBundle\Messenger\Middleware\LockableMessageMiddleware;
|
|
||||||
use RetailCrm\ServiceBundle\Tests\DataFixtures\TestMessage;
|
|
||||||
use Symfony\Component\Lock\Exception\LockConflictedException;
|
|
||||||
use Symfony\Component\Lock\Key;
|
|
||||||
use Symfony\Component\Lock\Lock;
|
|
||||||
use Symfony\Component\Lock\LockFactory;
|
|
||||||
use Symfony\Component\Lock\PersistingStoreInterface;
|
|
||||||
use Symfony\Component\Messenger\Envelope;
|
|
||||||
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
|
|
||||||
use Symfony\Component\Messenger\Middleware\StackInterface;
|
|
||||||
use Symfony\Component\Messenger\Stamp\ReceivedStamp;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class LockableMessageMiddlewareTest
|
|
||||||
*
|
|
||||||
* @package RetailCrm\ServiceBundle\Tests\Messenger\Middleware
|
|
||||||
*/
|
|
||||||
class LockableMessageMiddlewareTest extends TestCase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var LockFactory
|
|
||||||
*/
|
|
||||||
private $lockFactory;
|
|
||||||
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
$this->lockFactory = $this->createMock(LockFactory::class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testHandle(): void
|
|
||||||
{
|
|
||||||
$store = $this->createMock(PersistingStoreInterface::class);
|
|
||||||
$key = new Key(uniqid());
|
|
||||||
$lock = new Lock($key, $store);
|
|
||||||
$this->lockFactory->expects(static::once())->method('createLock')->willReturn($lock);
|
|
||||||
$envelope = new Envelope(new TestMessage(), [new ReceivedStamp('test')]);
|
|
||||||
|
|
||||||
$next = $this->createMock(MiddlewareInterface::class);
|
|
||||||
$next->method('handle')->willReturn($envelope);
|
|
||||||
$stack = $this->createMock(StackInterface::class);
|
|
||||||
$stack->method('next')->willReturn($next);
|
|
||||||
|
|
||||||
$middleware = new LockableMessageMiddleware($this->lockFactory);
|
|
||||||
$result = $middleware->handle($envelope, $stack);
|
|
||||||
|
|
||||||
static::assertInstanceOf(Envelope::class, $result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testLockHandle(): void
|
|
||||||
{
|
|
||||||
$store = $this->createMock(PersistingStoreInterface::class);
|
|
||||||
$store->method('save')->willThrowException(new LockConflictedException);
|
|
||||||
$key = new Key(uniqid());
|
|
||||||
$lock = new Lock($key, $store);
|
|
||||||
$this->lockFactory->expects(static::once())->method('createLock')->willReturn($lock);
|
|
||||||
$envelope = new Envelope(new TestMessage(), [new ReceivedStamp('test')]);
|
|
||||||
|
|
||||||
$next = $this->createMock(MiddlewareInterface::class);
|
|
||||||
$next->method('handle')->willReturn($envelope);
|
|
||||||
$stack = $this->createMock(StackInterface::class);
|
|
||||||
$stack->method('next')->willReturn($next);
|
|
||||||
|
|
||||||
$middleware = new LockableMessageMiddleware($this->lockFactory);
|
|
||||||
$result = $middleware->handle($envelope, $stack);
|
|
||||||
|
|
||||||
static::assertInstanceOf(Envelope::class, $result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testNonLockableHandle(): void
|
|
||||||
{
|
|
||||||
$store = $this->createMock(PersistingStoreInterface::class);
|
|
||||||
$store->method('save')->willThrowException(new LockConflictedException);
|
|
||||||
$key = new Key(uniqid());
|
|
||||||
$lock = new Lock($key, $store);
|
|
||||||
$this->lockFactory->expects(static::never())->method('createLock')->willReturn($lock);
|
|
||||||
$envelope = new Envelope(new \stdClass(), [new ReceivedStamp('test')]);
|
|
||||||
|
|
||||||
$next = $this->createMock(MiddlewareInterface::class);
|
|
||||||
$next->method('handle')->willReturn($envelope);
|
|
||||||
$stack = $this->createMock(StackInterface::class);
|
|
||||||
$stack->method('next')->willReturn($next);
|
|
||||||
|
|
||||||
$middleware = new LockableMessageMiddleware($this->lockFactory);
|
|
||||||
$result = $middleware->handle($envelope, $stack);
|
|
||||||
|
|
||||||
static::assertInstanceOf(Envelope::class, $result);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testNonReceivedHandle(): void
|
|
||||||
{
|
|
||||||
$store = $this->createMock(PersistingStoreInterface::class);
|
|
||||||
$store->method('save')->willThrowException(new LockConflictedException);
|
|
||||||
$key = new Key(uniqid());
|
|
||||||
$lock = new Lock($key, $store);
|
|
||||||
$this->lockFactory->expects(static::never())->method('createLock')->willReturn($lock);
|
|
||||||
$envelope = new Envelope(new TestMessage());
|
|
||||||
|
|
||||||
$next = $this->createMock(MiddlewareInterface::class);
|
|
||||||
$next->method('handle')->willReturn($envelope);
|
|
||||||
$stack = $this->createMock(StackInterface::class);
|
|
||||||
$stack->method('next')->willReturn($next);
|
|
||||||
|
|
||||||
$middleware = new LockableMessageMiddleware($this->lockFactory);
|
|
||||||
$result = $middleware->handle($envelope, $stack);
|
|
||||||
|
|
||||||
static::assertInstanceOf(Envelope::class, $result);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,13 +15,12 @@
|
||||||
"symfony/framework-bundle": "^4.0|^5.0",
|
"symfony/framework-bundle": "^4.0|^5.0",
|
||||||
"symfony/serializer": "^5.2",
|
"symfony/serializer": "^5.2",
|
||||||
"symfony/http-kernel": "^4.0|^5.0",
|
"symfony/http-kernel": "^4.0|^5.0",
|
||||||
"symfony/validator": "^4.0|^5.3",
|
"symfony/validator": "^4.0|^5.0",
|
||||||
"symfony/security-guard": "^4.0|^5.0",
|
"symfony/security-guard": "^4.0|^5.0",
|
||||||
"symfony/console": "^5.2",
|
"symfony/console": "^5.2",
|
||||||
"symfony/messenger": "^5.2",
|
"symfony/messenger": "^5.2",
|
||||||
"symfony/process": "^5.2",
|
"symfony/process": "^5.2",
|
||||||
"symfony/event-dispatcher": "^5.2",
|
"symfony/event-dispatcher": "^5.2"
|
||||||
"symfony/lock": "^5.2"
|
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": {
|
"psr-4": {
|
||||||
|
|
Loading…
Add table
Reference in a new issue