Skip to content

Commit

Permalink
feat(Cache ttl): update when reload cache
Browse files Browse the repository at this point in the history
  • Loading branch information
h4kuna committed Jan 19, 2024
1 parent d42e26f commit 9a515cc
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 31 deletions.
2 changes: 1 addition & 1 deletion src/Driver/Cnb/Day.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public function __construct(
ClientInterface $client,
RequestFactoryInterface $requestFactory,
string $timeZone = 'Europe/Prague',
string $refresh = 'today 15:00:00',
string $refresh = 'today 14:45:00',
)
{
parent::__construct($client, $requestFactory, $timeZone, $refresh);
Expand Down
2 changes: 1 addition & 1 deletion src/Driver/RB/Day.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public function __construct(
ClientInterface $client,
RequestFactoryInterface $requestFactory,
string $timeZone = 'Europe/Prague',
string $refresh = 'midnight, +1 minute',
string $refresh = 'midnight, +15 minute',
)
{
parent::__construct($client, $requestFactory, $timeZone, $refresh);
Expand Down
23 changes: 15 additions & 8 deletions src/RatingList/RatingList.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,12 @@

namespace h4kuna\Exchange\RatingList;

use ArrayAccess;
use DateTimeImmutable;
use Generator;
use h4kuna\Exchange\Currency\Property;
use h4kuna\Exchange\Exceptions\FrozenMethodException;
use IteratorAggregate;

/**
* @implements IteratorAggregate<string, Property>
* @implements ArrayAccess<string, Property>
*/
final class RatingList implements RatingListInterface, IteratorAggregate, ArrayAccess
final class RatingList implements RatingListInterface
{
/**
* @var array<string, bool>|null
Expand All @@ -24,6 +18,8 @@ final class RatingList implements RatingListInterface, IteratorAggregate, ArrayA

private ?DateTimeImmutable $date = null;

private ?DateTimeImmutable $expire = null;


public function __construct(private CacheEntity $cacheEntity, private RatingListCache $ratingListCache)
{
Expand Down Expand Up @@ -51,6 +47,7 @@ public function get(string $code): Property
public function all(): array
{
if ($this->all === null) {
$this->getDate(); // init cache
$this->all = $this->ratingListCache->all($this->cacheEntity);
}

Expand All @@ -61,12 +58,22 @@ public function all(): array
public function getDate(): DateTimeImmutable
{
if ($this->date === null) {
$this->date = $this->ratingListCache->build($this->cacheEntity);
[
'date' => $this->date,
'expire' => $this->expire,
] = $this->ratingListCache->build($this->cacheEntity);
}
return $this->date;
}


public function getExpire(): ?DateTimeImmutable
{
$this->getDate(); // init cache
return $this->expire;
}


/**
* @return Generator<string, Property>
* @deprecated moved to class Exchange
Expand Down
78 changes: 65 additions & 13 deletions src/RatingList/RatingListCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use h4kuna\CriticalCache\CacheLocking;
use h4kuna\CriticalCache\Utils\Dependency;
use h4kuna\Exchange\Currency\Property;
use h4kuna\Exchange\Driver\Driver;
use h4kuna\Exchange\Driver\DriverAccessor;
use h4kuna\Exchange\Exceptions\InvalidStateException;
use h4kuna\Exchange\Exceptions\UnknownCurrencyException;
Expand All @@ -14,9 +15,12 @@
use Psr\Http\Client\ClientExceptionInterface;
use Psr\SimpleCache\CacheInterface;

/**
* @phpstan-type cacheType array{date: DateTimeImmutable, expire: ?DateTimeImmutable, ttl: ?int}
*/
final class RatingListCache
{
public int $floatTtl = 600; // seconds -> 10 minutes
public int $floatTtl = 900; // seconds -> 15 minutes


/**
Expand All @@ -31,25 +35,39 @@ public function __construct(
}


public function build(CacheEntity $cacheEntity): DateTimeImmutable
/**
* @return cacheType
*
* @throws ClientExceptionInterface
*/
public function build(CacheEntity $cacheEntity): array
{
return $this->cache->load($cacheEntity->cacheKeyTtl, function (
Dependency $dependency,
CacheInterface $cache,
string $prefix,
) use ($cacheEntity): DateTimeImmutable {
[$date, $ttl] = $this->buildCache($cacheEntity, $cache, $prefix);
$dependency->ttl = $ttl;
) use ($cacheEntity): array {
$cacheType = $this->buildCache($cacheEntity, $cache, $prefix);
$dependency->ttl = $cacheType['ttl'];

return $date;
return $cacheType;
});
}


public function rebuild(CacheEntity $cacheEntity): void
/**
* @throws ClientExceptionInterface
*/
public function rebuild(CacheEntity $cacheEntity): bool
{
[$date, $ttl] = $this->buildCache($cacheEntity, $this->cache, '');
$this->cache->set($cacheEntity->cacheKeyTtl, $date, $ttl);
/**
* @var ?cacheType $cacheTypeOld
*/
$cacheTypeOld = $this->cache->get($cacheEntity->cacheKeyTtl);
$cacheType = $this->buildCache($cacheEntity, $this->cache, '');
$this->cache->set($cacheEntity->cacheKeyTtl, $cacheType, $cacheType['ttl']);

return $cacheTypeOld === null || $cacheTypeOld['expire']?->format(DATE_ATOM) !== $cacheType['expire']?->format(DATE_ATOM);
}


Expand Down Expand Up @@ -78,7 +96,9 @@ public function all(CacheEntity $cacheEntity): array


/**
* @return array{DateTimeImmutable, ?int}
* @return array{date: DateTimeImmutable, expire: ?DateTimeImmutable, ttl: ?int}
*
* @throws ClientExceptionInterface
*/
private function buildCache(CacheEntity $cacheEntity, CacheInterface $cache, string $prefix): array
{
Expand All @@ -93,16 +113,48 @@ private function buildCache(CacheEntity $cacheEntity, CacheInterface $cache, str
$data = $cache->get($prefix . $cacheEntity->cacheKeyAll) ?? [];

if ($cacheEntity->date === null && $data !== []) {
return [new DateTimeImmutable(), $this->floatTtl];
return self::makeCacheData(
new DateTimeImmutable(),
new DateTimeImmutable(sprintf('+%s seconds', $this->floatTtl)),
$this->floatTtl,
);
}
throw $e;
}

$cache->set($prefix . $cacheEntity->cacheKeyAll, $all);

return $cacheEntity->date === null
? [$provider->getDate(), Utils::countTTL($provider->getRefresh())]
: [$provider->getDate(), null];
? self::countCacheData($provider, $this->floatTtl)
: self::makeCacheData($provider->getDate());
}


/**
* @return cacheType
*/
private static function makeCacheData(
DateTimeImmutable $date,
?DateTimeImmutable $expire = null,
?int $ttl = null
): array
{
return [
'date' => $date,
'expire' => $expire,
'ttl' => $ttl,
];
}


/**
* @return cacheType
*/
private static function countCacheData(Driver $provider, int $floatTtl): array
{
$expire = $provider->getRefresh();
$ttl = Utils::countTTL($expire, $floatTtl);

return self::makeCacheData($provider->getDate(), DateTimeImmutable::createFromMutable($expire), $ttl);
}
}
11 changes: 10 additions & 1 deletion src/RatingList/RatingListInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@

namespace h4kuna\Exchange\RatingList;

use ArrayAccess;
use DateTimeImmutable;
use h4kuna\Exchange\Currency\Property;
use IteratorAggregate;

interface RatingListInterface
/**
* @extends IteratorAggregate<string, Property>
* @extends ArrayAccess<string, Property>
*/
interface RatingListInterface extends IteratorAggregate, ArrayAccess
{
/**
* @return self - clone or new object
Expand All @@ -24,4 +30,7 @@ function all(): array;

function getDate(): DateTimeImmutable;


function getExpire(): ?DateTimeImmutable;

}
6 changes: 3 additions & 3 deletions src/Utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ public static function transformCurrencies(array $currencies): array
/**
* @param int $beforeExpiration // 900 seconds -> 15 minutes
*/
public static function countTTL(DateTime $dateTime, int $beforeExpiration = 900): int
public static function countTTL(DateTime $dateTime, int $beforeExpiration = 900, int $time = null): int
{
$time = time();
$time ??= time();
if (($dateTime->getTimestamp() - $beforeExpiration) <= $time) {
$dateTime->modify('+1 day');
}

return $dateTime->getTimestamp() - time();
return $dateTime->getTimestamp() - $time;
}

}
9 changes: 7 additions & 2 deletions tests/src/Caching/CacheTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ public function testBasic(): void

$cacheEntity = new Exchange\RatingList\CacheEntity(null, Exchange\Driver\Cnb\Day::class);
$date = $cache->build($cacheEntity);
Assert::same('2022-12-21', $date->format('Y-m-d'));
Assert::same('2022-12-21', $date['date']->format('Y-m-d'));
$expected = new \DateTime('today 14:45:00');
Exchange\Utils::countTTL($expected);
assert(isset($date['expire']));
Assert::same($expected->format('Y-m-d H:i:s'), $date['expire']->format('Y-m-d H:i:s'));

$cache->rebuild($cacheEntity);

Expand All @@ -36,7 +40,8 @@ public function testHistory(): void
$cacheEntity = new Exchange\RatingList\CacheEntity(new \DateTime('2022-12-01'), Exchange\Driver\Cnb\Day::class);

$date = $cache->build($cacheEntity);
Assert::same('2022-12-01', $date->format('Y-m-d'));
Assert::same('2022-12-01', $date['date']->format('Y-m-d'));
Assert::null($date['expire']);

$cache->rebuild($cacheEntity);

Expand Down
27 changes: 25 additions & 2 deletions tests/src/UtilsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,24 @@ function (self $self) {
);
},
],
[
function (self $self) {
$self->assert(
87300,
new DateTime('2023-01-01 14:45:00'),
(new DateTime('2023-01-01 14:45:00, -900 seconds'))->getTimestamp(),
);
},
],
[
function (self $self) {
$self->assert(
901,
new DateTime('2023-01-01 14:45:00'),
(new DateTime('2023-01-01 14:45:00, -901 seconds'))->getTimestamp(),
);
},
],
];
}

Expand All @@ -52,10 +70,15 @@ public function testCountTTL(Closure $assert): void

public function assert(
int $expectedTime,
DateTime $from
DateTime $from,
int $time = 0
): void
{
Assert::same($expectedTime, Utils::countTTL($from));
if ($time === 0) {
Assert::same($expectedTime, Utils::countTTL($from, 900));
} else {
Assert::same($expectedTime, Utils::countTTL($from, 900, $time));
}
}
}

Expand Down

0 comments on commit 9a515cc

Please sign in to comment.