Skip to content

Commit

Permalink
Invalid cache before expiration
Browse files Browse the repository at this point in the history
  • Loading branch information
h4kuna committed Oct 25, 2023
1 parent 997c3c0 commit 90f8088
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 25 deletions.
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,19 @@ foreach ($exchange as $code => $property) {
var_dump($property);
}
```

## Caching

The cache invalid automatic at some time, defined by property `Driver::$refresh`. From this property is counted time to live. Little better is invalid cache by cron. Because one request on server does not lock other requests. Let's run cron max. 15 minutes before invalidate cache.
```php
use h4kuna\Exchange\RatingList\RatingListCache;
use h4kuna\Exchange\RatingList\CacheEntity;
use h4kuna\Exchange\Driver\Cnb\Day;

/** @var RatingListCache $ratingListCache */
$ratingListCache->rebuild(new CacheEntity(null, Day::class));
```

In example, is used `h4kuna\Exchange\Driver\Cnb\Day::$refresh` is defined at 15:00. Run cron 14:55 every day.


2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
"suggest": {
"guzzlehttp/guzzle": "As default implementation for PSR standards.",
"guzzlehttp/psr7": "Minimum ^2.4 for guzzle.",
"h4kuna/dir": "If you want to use build-in factory.",
"nette/caching": "If you have not own PSR-6 implementation.",
"ext-simplexml": "If you want to use h4kuna\\Exchange\\Driver\\Ecb."
},
"autoload-dev": {
Expand Down
4 changes: 3 additions & 1 deletion src/Driver/Cnb/Day.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class Day extends Exchange\Driver\Driver
{
// private const URL_DAY_OTHER = 'http://www.cnb.cz/cs/financni_trhy/devizovy_trh/kurzy_ostatnich_men/kurzy.txt';

public static string $url = 'https://www.cnb.cz/cs/financni_trhy/devizovy_trh/kurzy_devizoveho_trhu/denni_kurz.txt';

protected string $refresh = 'today 15:00:00';

protected string $timeZone = 'Europe/Prague';
Expand Down Expand Up @@ -47,7 +49,7 @@ protected function createProperty($row): Property

protected function prepareUrl(?\DateTimeInterface $date): string
{
$url = 'https://www.cnb.cz/cs/financni_trhy/devizovy_trh/kurzy_devizoveho_trhu/denni_kurz.txt';
$url = self::$url;

if ($date === null) {
return $url;
Expand Down
19 changes: 11 additions & 8 deletions src/Driver/Driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
namespace h4kuna\Exchange\Driver;

use DateTime;
use DateTimeImmutable;
use DateTimeInterface;
use DateTimeZone;
use Generator;
use h4kuna\Exchange;
Expand All @@ -20,7 +22,7 @@
abstract class Driver
{

private \DateTimeImmutable $date;
private DateTimeImmutable $date;

protected string $timeZone = 'UTC';

Expand All @@ -43,14 +45,14 @@ public function __construct(
/**
* @throws ClientExceptionInterface
*/
public function initRequest(?\DateTimeInterface $date): void
public function initRequest(?DateTimeInterface $date): void
{
$content = $this->client->sendRequest($this->createRequest($date));
$this->list = $this->createList($content);
}


public function getDate(): \DateTimeImmutable
public function getDate(): DateTimeImmutable
{
return $this->date;
}
Expand Down Expand Up @@ -84,7 +86,7 @@ public function getRefresh(): DateTime

protected function setDate(string $format, string $value): void
{
$date = \DateTimeImmutable::createFromFormat($format, $value, new DateTimeZone($this->timeZone));
$date = DateTimeImmutable::createFromFormat($format, $value, new DateTimeZone($this->timeZone));
if ($date === false) {
throw new Exchange\Exceptions\InvalidStateException(sprintf('Can not create DateTime object from source "%s" with format "%s".', $value, $format));
}
Expand All @@ -105,14 +107,15 @@ abstract protected function createList(ResponseInterface $response): iterable;
abstract protected function createProperty($row);


abstract protected function prepareUrl(?\DateTimeInterface $date): string;
abstract protected function prepareUrl(?DateTimeInterface $date): string;


private function createRequest(?\DateTimeInterface $date): RequestInterface
private function createRequest(?DateTimeInterface $date): RequestInterface
{
if ($date !== null && $date->getTimezone()->getName() !== $this->timeZone) {
$date = new DateTime('@' . $date->getTimestamp(), new DateTimeZone('UTC'));
$date->setTimezone(new DateTimeZone($this->timeZone));
$tmp = new DateTime('now', new DateTimeZone($this->timeZone));
$tmp->setTimestamp($date->getTimestamp());
$date = $tmp;
}

$request = $this->requestFactory->createRequest('GET', $this->prepareUrl($date));
Expand Down
1 change: 0 additions & 1 deletion src/Driver/DriverBuilderFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ protected function getRequestFactory(): RequestFactoryInterface
{
if ($this->requestFactory === null) {
MissingDependencyException::guzzleFactory();

$this->requestFactory = new HttpFactory();
}

Expand Down
4 changes: 3 additions & 1 deletion src/Driver/Ecb/Day.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class Day extends Exchange\Driver\Driver
{
protected string $timeZone = 'Europe/Berlin';

public static string $url = 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml';


/**
* @return iterable<\SimpleXMLElement>
Expand Down Expand Up @@ -55,7 +57,7 @@ protected function prepareUrl(?\DateTimeInterface $date): string
throw new Exchange\Exceptions\InvalidStateException('Ecb does not support history.');
}

return 'http://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml';
return self::$url;
}

}
3 changes: 3 additions & 0 deletions src/RatingList/CacheEntity.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

use DateTimeInterface;

/**
* readonly php 8.2+
*/
final class CacheEntity
{
public ?DateTimeInterface $date;
Expand Down
18 changes: 4 additions & 14 deletions src/RatingList/RatingListCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@

namespace h4kuna\Exchange\RatingList;

use DateTime;
use DateTimeImmutable;
use h4kuna\CriticalCache\CacheLocking;
use h4kuna\CriticalCache\Utils\Dependency;
use h4kuna\Exchange\Currency\Property;
use h4kuna\Exchange\Driver\DriverAccessor;
use h4kuna\Exchange\Exceptions\InvalidStateException;
use h4kuna\Exchange\Exceptions\UnknownCurrencyException;
use h4kuna\Exchange\Utils;
use h4kuna\Serialize\Serialize;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\SimpleCache\CacheInterface;

final class RatingListCache
{
public int $floatTtl = 600;
public int $floatTtl = 600; // seconds -> 10 minutes


/**
Expand Down Expand Up @@ -89,7 +89,7 @@ private function buildCache(CacheEntity $cacheEntity, CacheInterface $cache, str
$data = $cache->get($prefix . $cacheEntity->cacheKeyAll) ?? [];

if ($cacheEntity->date === null && $data !== []) {
return [new DateTimeImmutable(), time() + $this->floatTtl];
return [new DateTimeImmutable(), $this->floatTtl];
}
throw $e;
}
Expand All @@ -103,18 +103,8 @@ private function buildCache(CacheEntity $cacheEntity, CacheInterface $cache, str
$cache->set($prefix . $cacheEntity->cacheKeyAll, $all);

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


private static function countTTL(DateTime $dateTime): int
{
if ($dateTime->getTimestamp() < time()) {
$dateTime->modify('+1 day');
}

return $dateTime->getTimestamp();
}

}
14 changes: 14 additions & 0 deletions src/Utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace h4kuna\Exchange;

use DateTime;
use h4kuna\DataType\Basic\Strings;
use Nette\StaticClass;

Expand Down Expand Up @@ -30,4 +31,17 @@ public static function transformCurrencies(array $currencies): array
return array_flip(array_map(fn (string $v) => strtoupper($v), $currencies));
}


/**
* @param int $beforeExpiration // 900 seconds -> 15 minutes
*/
public static function countTTL(DateTime $dateTime, int $beforeExpiration = 900): int
{
if ($dateTime->getTimestamp() < (time() - $beforeExpiration)) {
$dateTime->modify('+1 day');
}

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

}
21 changes: 21 additions & 0 deletions tests/src/Driver/Cnb/DayTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

namespace h4kuna\Exchange\Tests\Driver\Cnb;

use GuzzleHttp\Client;
use GuzzleHttp\Psr7\HttpFactory;
use h4kuna\Exchange\Driver\Cnb\Day;
use h4kuna\Exchange\Utils;
use Tester\Assert;
use Tester\TestCase;

Expand All @@ -20,6 +24,23 @@ public function testDownloadHistory(): void
Assert::same('2022-12-01', $exchange->getDate()->format('Y-m-d'));
}


public function testRefresh(): void
{
$client = new HttpFactory();
$day = new Day(new Client(), $client);

Assert::same((new \DateTime('now', new \DateTimeZone('Europe/Prague')))->format('Y-m-d'), $day->getRefresh()->format('Y-m-d'));

$prevTtl = 900;
$refresh = new \DateTime('today 15:00:00', new \DateTimeZone('Europe/Prague'));
if ($refresh->getTimestamp() < (time() - $prevTtl)) {
$refresh->modify('+1 day');
}

Assert::same($refresh->getTimestamp() - time(), Utils::countTTL($day->getRefresh(), $prevTtl));
}

}

(new DayTest())->run();
29 changes: 29 additions & 0 deletions tests/src/TimestampTimeZoneTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php declare(strict_types=1);

namespace h4kuna\Exchange\Tests;

use DateTime;
use DateTimeZone;
use Tester\Assert;
use Tester\TestCase;

require __DIR__ . '/../bootstrap.php';

/**
* @testCase
*/
final class TimestampTimeZoneTest extends TestCase
{
public function testDefault(): void
{
$date = new DateTime('1986-12-30 5:30:57', new DateTimeZone('America/Adak'));

$newDate = new DateTime('now', new DateTimeZone('Europe/Prague'));
$newDate->setTimestamp($date->getTimestamp());

Assert::same('1986-12-30 05:30:57', $date->format('Y-m-d H:i:s'));
Assert::same('1986-12-30 16:30:57', $newDate->format('Y-m-d H:i:s'));
}
}

(new TimestampTimeZoneTest)->run();

0 comments on commit 90f8088

Please sign in to comment.