8000 [Lock][Semaphore] Add Factory::createFromKey and deprecate lock.store services by jderusse · Pull Request #38593 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Lock][Semaphore] Add Factory::createFromKey and deprecate lock.store services #38593

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion UPGRADE-5.2.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ FrameworkBundle
keep cache namespaces separated by environment of the app. The `%kernel.container_class%` (which includes the environment)
used to be added by default to the seed, which is not the case anymore. This allows sharing caches between
apps or different environments.
* Deprecated the `lock.RESOURCE_NAME` service and the `lock` and `LockInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead.
* Deprecated the `lock.RESOURCE_NAME` and `lock.RESOURCE_NAME.store` services and the `lock`, `LockInterface`, `lock.store` and `PersistingStoreInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead.

Form
----
Expand Down
2 changes: 1 addition & 1 deletion UPGRADE-6.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ FrameworkBundle
* Removed `session.attribute_bag` service and `session.flash_bag` service.
* The `form.factory`, `form.type.file`, `translator`, `security.csrf.token_manager`, `serializer`,
`cache_clearer`, `filesystem` and `validator` services are now private.
* Removed the `lock.RESOURCE_NAME` service and the `lock` and `LockInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead.
* Removed the `lock.RESOURCE_NAME` and `lock.RESOURCE_NAME.store` services and the `lock`, `LockInterface`, `lock.store` and `PersistingStoreInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead.

HttpFoundation
--------------
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ CHANGELOG
* added `assertCheckboxChecked()` and `assertCheckboxNotChecked()` in `WebTestCase`
* added `assertFormValue()` and `assertNoFormValue()` in `WebTestCase`
* Added "--as-tree=3" option to `translation:update` command to dump messages as a tree-like structure. The given value defines the level where to switch to inline YAML
* Deprecated the `lock.RESOURCE_NAME` service and the `lock` and `LockInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead.
* Deprecated the `lock.RESOURCE_NAME` and `lock.RESOURCE_NAME.store` services and the `lock`, `LockInterface`, `lock.store` and `PersistingStoreInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead.

5.1.0
-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1674,14 +1674,15 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont
if (\count($storeDefinitions) > 1) {
$combinedDefinition = new ChildDefinition('lock.store.combined.abstract');
$combinedDefinition->replaceArgument(0, $storeDefinitions);
$container->setDefinition('lock.'.$resourceName.'.store', $combinedDefinition);
$container->setDefinition('lock.'.$resourceName.'.store', $combinedDefinition)->setDeprecated('symfony/framework-bundle', '5.2', 'The "%service_id%" service is deprecated, use "lock.'.$resourceName.'.factory" instead.');
$container->setDefinition($storeDefinitionId = '.lock.'.$resourceName.'.store.'.$container->hash($resourceStores), $combinedDefinition);
} else {
$container->setAlias('lock.'.$resourceName.'.store', new Alias((string) $storeDefinitions[0], false));
$container->setAlias('lock.'.$resourceName.'.store', (new Alias($storeDefinitionId, false))->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "lock.'.$resourceName.'.factory" instead.'));
}

// Generate factories for each resource
$factoryDefinition = new ChildDefinition('lock.factory.abstract');
$factoryDefinition->replaceArgument(0, new Reference('lock.'.$resourceName.'.store'));
$factoryDefinition->replaceArgument(0, new Reference($storeDefinitionId));
$container->setDefinition('lock.'.$resourceName.'.factory', $factoryDefinition);

// Generate services for lock instances
Expand All @@ -1693,14 +1694,14 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont

// provide alias for default resource
if ('default' === $resourceName) {
$container->setAlias('lock.store', new Alias('lock.'.$resourceName.'.store', false));
$container->setAlias('lock.store', (new Alias($storeDefinitionId, false))->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "lock.factory" instead.'));
$container->setAlias('lock.factory', new Alias('lock.'.$resourceName.'.factory', false));
$container->setAlias('lock', (new Alias('lock.'.$resourceName, false))->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "lock.factory" instead.'));
$container->setAlias(PersistingStoreInterface::class, new Alias('lock.store', false));
$container->setAlias(PersistingStoreInterface::class, (new Alias($storeDefinitionId, false))->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "'.LockFactory::class.'" instead.'));
$container->setAlias(LockFactory::class, new Alias('lock.factory', false));
$container->setAlias(LockInterface::class, (new Alias('lock.'.$resourceName, false))->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "'.LockFactory::class.'" instead.'));
} else {
$container->registerAliasForArgument('lock.'.$resourceName.'.store', PersistingStoreInterface::class, $resourceName.'.lock.store');
$container->registerAliasForArgument($storeDefinitionId, PersistingStoreInterface::class, $resourceName.'.lock.store')->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "'.LockFactory::class.' '.$resourceName.'LockFactory" instead.');
$container->registerAliasForArgument('lock.'.$resourceName.'.factory', LockFactory::class, $resourceName.'.lock.factory');
$container->registerAliasForArgument('lock.'.$resourceName, LockInterface::class, $resourceName.'.lock')->setDeprecated('symfony/framework-bundle', '5.2', 'The "%alias_id%" alias is deprecated, use "'.LockFactory::class.' $'.$resourceName.'LockFactory" instead.');
}
Expand Down
1 change: 1 addition & 0 deletions src/Symfony/Component/Lock/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ CHANGELOG
* deprecated `RetryTillSaveStore`, logic has been moved in `Lock` and is not needed anymore.
* added `InMemoryStore`
* added `PostgreSqlStore`
* added the `LockFactory::CreateLockFromKey()` method.

5.1.0
-----
Expand Down
14 changes: 13 additions & 1 deletion src/Symfony/Component/Lock/LockFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,19 @@ public function __construct(PersistingStoreInterface $store)
*/
public function createLock(string $resource, ?float $ttl = 300.0, bool $autoRelease = true): LockInterface
{
$lock = new Lock(new Key($resource), $this->store, $ttl, $autoRelease);
return $this->createLockFromKey(new Key($resource), $ttl, $autoRelease);
}

/**
* Creates a lock from the given key.
*
* @param Key $key The key containing the lock's state
* @param float|null $ttl Maximum expected lock duration in seconds
* @param bool $autoRelease Whether to automatically release the lock or not when the lock instance is destroyed
*/
public function createLockFromKey(Key $key, ?float $ttl = 300.0, bool $autoRelease = true): LockInterface
{
$lock = new Lock($key, $this->store, $ttl, $autoRelease);
$lock->setLogger($this->logger);

return $lock;
Expand Down
55 changes: 52 additions & 3 deletions src/Symfony/Component/Lock/Tests/LockFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Symfony\Component\Lock\Key;
use Symfony\Component\Lock\LockFactory;
use Symfony\Component\Lock\LockInterface;
use Symfony\Component\Lock\PersistingStoreInterface;

/**
Expand All @@ -25,12 +25,61 @@ class LockFactoryTest extends TestCase
public function testCreateLock()
{
$store = $this->getMockBuilder(PersistingStoreInterface::class)->getMock();
$store->expects($this->any())->method('exists')->willReturn(false);

$keys = [];
$store
->expects($this->exactly(2))
->method('save')
->with($this->callbac F438 k(function ($key) use (&$keys) {
$keys[] = $key;

return true;
}))
->willReturn(true);

$logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
$factory = new LockFactory($store);
$factory->setLogger($logger);

$lock = $factory->createLock('foo');
$lock1 = $factory->createLock('foo');
$lock2 = $factory->createLock('foo');

// assert lock1 and lock2 don't share the same state
$lock1->acquire();
$lock2->acquire();

$this->assertNotSame($keys[0], $keys[1]);
}

public function testCreateLockFromKey()
{
$store = $this->getMockBuilder(PersistingStoreInterface::class)->getMock();
$store->expects($this->any())->method('exists')->willReturn(false);

$keys = [];
$store
->expects($this->exactly(2))
->method('save')
->with($this->callback(function ($key) use (&$keys) {
$keys[] = $key;

return true;
}))
->willReturn(true);

$logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
$factory = new LockFactory($store);
$factory->setLogger($logger);

$key = new Key('foo');
$lock1 = $factory->createLockFromKey($key);
$lock2 = $factory->createLockFromKey($key);

// assert lock1 and lock2 share the same state
$lock1->acquire();
$lock2->acquire();

$this->assertInstanceOf(LockInterface::class, $lock);
$this->assertSame($keys[0], $keys[1]);
}
}
11 changes: 10 additions & 1 deletion src/Symfony/Component/Semaphore/SemaphoreFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,16 @@ public function __construct(PersistingStoreInterface $store)
*/
public function createSemaphore(string $resource, int $limit, int $weight = 1, ?float $ttlInSecond = 300.0, bool $autoRelease = true): SemaphoreInterface
{
$semaphore = new Semaphore(new Key($resource, $limit, $weight), $this->store, $ttlInSecond, $autoRelease);
return $this->createSemaphoreFromKey(new Key($resource, $limit, $weight), $ttlInSecond, $autoRelease);
}

/**
* @param float|null $ttlInSecond Maximum expected semaphore duration in seconds
* @param bool $autoRelease Whether to automatically release the semaphore or not when the semaphore instance is destroyed
*/
public function createSemaphoreFromKey(Key $key, ?float $ttlInSecond = 300.0, bool $autoRelease = true): SemaphoreInterface
{
$semaphore = new Semaphore($key, $this->store, $ttlInSecond, $autoRelease);
$semaphore->setLogger($this->logger);

return $semaphore;
Expand Down
53 changes: 50 additions & 3 deletions src/Symfony/Component/Semaphore/Tests/SemaphoreFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@

use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Symfony\Component\Semaphore\Key;
use Symfony\Component\Semaphore\PersistingStoreInterface;
use Symfony\Component\Semaphore\SemaphoreFactory;
use Symfony\Component\Semaphore\SemaphoreInterface;

/**
* @author Jérémy Derussé <jeremy@derusse.com>
Expand All @@ -26,12 +26,59 @@ class SemaphoreFactoryTest extends TestCase
public function testCreateSemaphore()
{
$store = $this->getMockBuilder(PersistingStoreInterface::class)->getMock();

$keys = [];
$store
->expects($this->exactly(2))
->method('save')
->with($this->callback(function ($key) use (&$keys) {
$keys[] = $key;

return true;
}))
->willReturn(true);

$logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
$factory = new SemaphoreFactory($store);
$factory->setLogger($logger);

$semaphore = $factory->createSemaphore('foo', 4);
$semaphore1 = $factory->createSemaphore('foo', 4);
$semaphore2 = $factory->createSemaphore('foo', 4);

// assert lock1 and lock2 don't share the same state
$semaphore1->acquire();
$semaphore2->acquire();

$this->assertNotSame($keys[0], $keys[1]);
}

public function testCreateSemaphoreFromKey()
{
$store = $this->getMockBuilder(PersistingStoreInterface::class)->getMock();

$keys = [];
$store
->expects($this->exactly(2))
->method('save')
->with($this->callback(function ($key) use (&$keys) {
$keys[] = $key;

return true;
}))
->willReturn(true);

$logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
$factory = new SemaphoreFactory($store);
$factory->setLogger($logger);

$key = new Key('foo', 4);
$semaphore1 = $factory->createSemaphoreFromKey($key);
$semaphore2 = $factory->createSemaphoreFromKey($key);

// assert lock1 and lock2 share the same state
$semaphore1->acquire();
$semaphore2->acquire();

$this->assertInstanceOf(SemaphoreInterface::class, $semaphore);
$this->assertSame($keys[0], $keys[1]);
}
}
0