Skip to content

Commit 8064cf9

Browse files
authored
Add a cache layer on top of SSM (#580)
* Add a cache layer on top of SSM * Fix CI * Use cache.system as default value
1 parent a62b159 commit 8064cf9

File tree

6 files changed

+88
-1
lines changed

6 files changed

+88
-1
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
"async-aws/sqs": "^1.0",
2525
"async-aws/ssm": "^0.1",
2626
"matthiasnoback/symfony-config-test": "^4.1",
27-
"nyholm/symfony-bundle-test": "^1.6.1"
27+
"nyholm/symfony-bundle-test": "^1.6.1",
28+
"symfony/cache": "^4.4 || ^5.0"
2829
},
2930
"extra": {
3031
"branch-alias": {

src/DependencyInjection/AsyncAwsExtension.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44

55
namespace AsyncAws\Symfony\Bundle\DependencyInjection;
66

7+
use AsyncAws\Symfony\Bundle\Secrets\CachedEnvVarLoader;
78
use AsyncAws\Symfony\Bundle\Secrets\SsmVault;
89
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
910
use Symfony\Component\DependencyInjection\ContainerBuilder;
1011
use Symfony\Component\DependencyInjection\ContainerInterface;
1112
use Symfony\Component\DependencyInjection\Definition;
1213
use Symfony\Component\DependencyInjection\Reference;
1314
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
15+
use Symfony\Contracts\Cache\CacheInterface;
1416

1517
class AsyncAwsExtension extends Extension
1618
{
@@ -137,6 +139,20 @@ private function registerEnvLoader(ContainerBuilder $container, array $config):
137139
$config['secrets']['path'],
138140
$config['secrets']['recursive'],
139141
]);
142+
143+
if ($config['secrets']['cache']['enabled']) {
144+
if (!\interface_exists(CacheInterface::class)) {
145+
throw new InvalidConfigurationException(sprintf('You have enabled "async_aws.secrets.cache" but the "symfony/cache" package is not installed. Try running "composer require symfony/cache"'));
146+
}
147+
148+
$container->Register(CachedEnvVarLoader::class)
149+
->setDecoratedService(SsmVault::class)
150+
->setArguments([
151+
new Reference(CachedEnvVarLoader::class . '.inner'),
152+
new Reference($config['secrets']['cache']['pool']),
153+
$config['secrets']['cache']['ttl'],
154+
]);
155+
}
140156
}
141157

142158
private function autowireServices(ContainerBuilder $container, array $usedServices): void

src/DependencyInjection/Configuration.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ public function getConfigTreeBuilder()
4848
->scalarNode('path')->info('Path to the parameters.')->defaultNull()->end()
4949
->booleanNode('recursive')->info('Retrieve all parameters within a hierarchy.')->defaultValue(true)->end()
5050
->scalarNode('client')->info('Name of the SSM client. When null, use the default SSM configuration.')->defaultNull()->end()
51+
->arrayNode('cache')
52+
->canBeEnabled()
53+
->children()
54+
->scalarNode('pool')->info('Identifier of the Symfony Cache Pool.')->defaultValue('cache.system')->end()
55+
->integerNode('ttl')->info('Duration of cache in seconds')->min(0)->defaultValue(600)->end()
56+
->end()
57+
->end()
5158
->end()
5259
->end()
5360
->end();

src/Secrets/CachedEnvVarLoader.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
namespace AsyncAws\Symfony\Bundle\Secrets;
4+
5+
use Symfony\Component\DependencyInjection\EnvVarLoaderInterface;
6+
use Symfony\Contracts\Cache\CacheInterface;
7+
use Symfony\Contracts\Cache\ItemInterface;
8+
9+
class CachedEnvVarLoader implements EnvVarLoaderInterface
10+
{
11+
private $decorated;
12+
13+
private $cache;
14+
15+
private $ttl;
16+
17+
public function __construct(EnvVarLoaderInterface $decorated, CacheInterface $cache, int $ttl)
18+
{
19+
$this->decorated = $decorated;
20+
$this->cache = $cache;
21+
$this->ttl = $ttl;
22+
}
23+
24+
public function loadEnvVars(): array
25+
{
26+
return $this->cache->get('AsyncAws.Secrets', function (ItemInterface $item) {
27+
$item->expiresAfter($this->ttl);
28+
29+
return $this->decorated->loadEnvVars();
30+
});
31+
}
32+
}

tests/Unit/DependencyInjection/ConfigurationTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ public function testDefaultValues(): void
3333
'path' => null,
3434
'recursive' => true,
3535
'client' => null,
36+
'cache' => [
37+
'enabled' => false,
38+
'pool' => 'cache.system',
39+
'ttl' => 600,
40+
],
3641
],
3742
]);
3843
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace AsyncAws\Symfony\Bundle\Tests\Unit\Secrets;
4+
5+
use AsyncAws\Symfony\Bundle\Secrets\CachedEnvVarLoader;
6+
use AsyncAws\Symfony\Bundle\Secrets\SsmVault;
7+
use PHPUnit\Framework\TestCase;
8+
use Symfony\Component\Cache\Adapter\ArrayAdapter;
9+
10+
class CachedEnvVarLoaderTest extends TestCase
11+
{
12+
public function testLoadEnvVars()
13+
{
14+
$env = ['FOO' => 'bar'];
15+
$decorated = $this->createMock(SsmVault::class);
16+
$decorated->expects(self::once())
17+
->method('loadEnvVars')
18+
->willReturn($env);
19+
20+
$envLoader = new CachedEnvVarLoader($decorated, new ArrayAdapter(), 5);
21+
22+
self::assertSame($env, $envLoader->loadEnvVars());
23+
// call it twice to assert decorated is called once
24+
self::assertSame($env, $envLoader->loadEnvVars());
25+
}
26+
}

0 commit comments

Comments
 (0)