Skip to content
This repository was archived by the owner on Jun 23, 2025. It is now read-only.

Commit faf5675

Browse files
committed
add RefreshFeatures middleware, that can run during shutdown
1 parent c24d454 commit faf5675

File tree

2 files changed

+66
-37
lines changed

2 files changed

+66
-37
lines changed

src/Middleware/RefreshFeatures.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
namespace MikeFrancis\LaravelUnleash\Middleware;
4+
5+
use Closure;
6+
use Illuminate\Http\Request;
7+
use MikeFrancis\LaravelUnleash\Unleash;
8+
9+
class RefreshFeatures
10+
{
11+
public float $ttlThresholdFactor = 0.75; // when ttl has reached 75%, refresh the cache
12+
13+
public function handle(Request $request, Closure $next)
14+
{
15+
return $next($request);
16+
}
17+
18+
public function terminate()
19+
{
20+
$unleash = app('unleash');
21+
if (!$unleash instanceof Unleash) {
22+
return;
23+
}
24+
if (time() + ($unleash->getCacheTTL() * $this->ttlThresholdFactor) > $unleash->getExpires()) {
25+
$unleash->refreshCache();
26+
}
27+
}
28+
}

src/Unleash.php

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212
use MikeFrancis\LaravelUnleash\Strategies\Contracts\DynamicStrategy;
1313
use MikeFrancis\LaravelUnleash\Strategies\Contracts\Strategy;
1414
use Symfony\Component\HttpFoundation\Exception\JsonException;
15+
1516
use function GuzzleHttp\json_decode;
1617

1718
class Unleash
1819
{
19-
const DEFAULT_CACHE_TTL = 15;
20+
public const DEFAULT_CACHE_TTL = 15;
2021

2122
protected $client;
2223
protected $cache;
@@ -39,20 +40,26 @@ public function getFeatures(): array
3940
return $this->features;
4041
}
4142

42-
try {
43-
$this->features = $this->getCachedFeatures();
44-
45-
// Always store the failover cache, in case it is turned on during failure scenarios.
46-
$this->cache->forever('unleash.features.failover', $this->features);
43+
if (!$this->config->get('unleash.isEnabled')) {
44+
return [];
45+
}
4746

48-
return $this->features;
49-
} catch (TransferException | JsonException $e) {
47+
try {
48+
if ($this->config->get('unleash.cache.isEnabled')) {
49+
$data = $this->getCachedFeatures();
50+
} else {
51+
$data = $this->fetchFeatures();
52+
}
53+
} catch (TransferException | JsonException) {
5054
if ($this->config->get('unleash.cache.failover') === true) {
51-
return $this->cache->get('unleash.features.failover', []);
55+
$data = $this->cache->get('unleash.failover', []);
5256
}
5357
}
5458

55-
return [];
59+
$this->features = Arr::get($data, 'features', []);
60+
$this->expires = Arr::get($data, 'expires', $this->getExpires());
61+
62+
return $this->features;
5663
}
5764

5865
public function getFeature(string $name)
@@ -93,7 +100,7 @@ public function isFeatureEnabled(string $name, ...$args): bool
93100
if (is_callable($allStrategies[$className])) {
94101
$strategy = $allStrategies[$className]();
95102
} else {
96-
$strategy = new $allStrategies[$className];
103+
$strategy = new $allStrategies[$className]();
97104
}
98105

99106
if (!$strategy instanceof Strategy && !$strategy instanceof DynamicStrategy) {
@@ -115,40 +122,34 @@ public function isFeatureDisabled(string $name, ...$args): bool
115122
return !$this->isFeatureEnabled($name, ...$args);
116123
}
117124

125+
public function refreshCache()
126+
{
127+
$this->fetchFeatures();
128+
}
129+
118130
protected function isFresh(): bool
119131
{
120132
return $this->expires > time();
121133
}
122134

123135
protected function getCachedFeatures(): array
124136
{
125-
if (!$this->config->get('unleash.isEnabled')) {
126-
return [];
127-
}
128-
129-
if ($this->config->get('unleash.cache.isEnabled')) {
130-
$this->setExpires();
131-
132-
return $this->cache->remember(
133-
'unleash',
134-
$this->getCacheTTL(),
135-
function () {
136-
return $this->fetchFeatures();
137-
}
138-
);
139-
}
140-
141-
return $this->features ?? $this->features = $this->fetchFeatures();
137+
return $this->cache->get('unleash.cache', function () {return $this->fetchFeatures();});
142138
}
143139

144-
protected function getCacheTTL(): int
140+
public function getCacheTTL(): int
145141
{
146142
return $this->config->get('unleash.cache.ttl', self::DEFAULT_CACHE_TTL);
147143
}
148144

149-
protected function setExpires(): void
145+
protected function setExpires(): int
150146
{
151-
$this->expires = $this->getCacheTTL() + time();
147+
return $this->expires = $this->getCacheTTL() + time();
148+
}
149+
150+
public function getExpires(): int
151+
{
152+
return $this->expires ?? $this->setExpires();
152153
}
153154

154155
protected function fetchFeatures(): array
@@ -161,13 +162,13 @@ protected function fetchFeatures(): array
161162
throw new JsonException('Could not decode unleash response body.', $e->getCode(), $e);
162163
}
163164

164-
$this->setExpires();
165+
$data['expires'] = $this->setExpires();
165166

166-
return $this->formatResponse($data);
167-
}
167+
$this->cache->set('unleash.cache', $data, $this->getCacheTTL());
168+
$this->cache->forever('unleash.failover', $data);
168169

169-
protected function formatResponse($data): array
170-
{
171-
return Arr::get($data, 'features', []);
170+
$this->features = Arr::get($data, 'features', []);
171+
172+
return $data;
172173
}
173174
}

0 commit comments

Comments
 (0)