fix: skip snapshots of travels still available as XML from refreshing

This commit is contained in:
Björn Fromme
2026-03-23 19:15:45 +01:00
parent 77b16f287a
commit be43d30cc7
3 changed files with 39 additions and 3 deletions
@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace App\Command; namespace App\Command;
use App\BusProNet\XmlLoader\TravelLoader;
use App\Service\TravelSnapshotService; use App\Service\TravelSnapshotService;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Attribute\AsCommand;
@@ -28,6 +29,7 @@ class BpnRefreshTravelSnapshotCommand extends Command
public function __construct( public function __construct(
private readonly TravelSnapshotService $snapshotService, private readonly TravelSnapshotService $snapshotService,
private readonly LoggerInterface $logger, private readonly LoggerInterface $logger,
private readonly TravelLoader $travelLoader,
) { ) {
parent::__construct(); parent::__construct();
} }
@@ -54,7 +56,16 @@ class BpnRefreshTravelSnapshotCommand extends Command
$force = true === $input->getOption('force'); $force = true === $input->getOption('force');
$refreshAfterMinutes = (int) $input->getOption('refresh-after'); $refreshAfterMinutes = (int) $input->getOption('refresh-after');
$result = $this->snapshotService->refreshExtendedSnapshots($limit, $force, $refreshAfterMinutes); $xmlDateIds = [];
try {
$xmlDateIds = array_keys($this->travelLoader->generateFilesMap());
} catch (\Throwable $e) {
$this->logger->warning('Failed to load XML files map for snapshot refresh filtering; refreshing all snapshots', [
'error' => $e->getMessage(),
]);
}
$result = $this->snapshotService->refreshExtendedSnapshots($limit, $force, $refreshAfterMinutes, $xmlDateIds);
$io->success(sprintf( $io->success(sprintf(
'Snapshot refresh complete: %d processed, %d updated, %d failed', 'Snapshot refresh complete: %d processed, %d updated, %d failed',
+8 -2
View File
@@ -175,7 +175,7 @@ class TravelSnapshotService
* *
* @return array{processed:int,updated:int,failed:int} * @return array{processed:int,updated:int,failed:int}
*/ */
public function refreshExtendedSnapshots(int $limit = 500, bool $force = false, int $refreshAfterMinutes = 360): array public function refreshExtendedSnapshots(int $limit = 500, bool $force = false, int $refreshAfterMinutes = 360, array $xmlAvailableDateIds = []): array
{ {
$dateToThreshold = new \DateTimeImmutable(sprintf('-%d days', $this->retentionBufferDays)); $dateToThreshold = new \DateTimeImmutable(sprintf('-%d days', $this->retentionBufferDays));
$refreshBefore = new \DateTimeImmutable(sprintf('-%d minutes', $refreshAfterMinutes)); $refreshBefore = new \DateTimeImmutable(sprintf('-%d minutes', $refreshAfterMinutes));
@@ -184,12 +184,18 @@ class TravelSnapshotService
? $this->snapshotRepository->findAllForMapping($limit) ? $this->snapshotRepository->findAllForMapping($limit)
: $this->snapshotRepository->findRefreshCandidates($dateToThreshold, $refreshBefore, $limit); : $this->snapshotRepository->findRefreshCandidates($dateToThreshold, $refreshBefore, $limit);
$processed = 0;
$updated = 0; $updated = 0;
$failed = 0; $failed = 0;
/** @var array<int, ExtendedServiceAvailabilityResponse|null> $extendedResponseByDateId */ /** @var array<int, ExtendedServiceAvailabilityResponse|null> $extendedResponseByDateId */
$extendedResponseByDateId = []; $extendedResponseByDateId = [];
foreach ($candidates as $snapshot) { foreach ($candidates as $snapshot) {
if ([] !== $xmlAvailableDateIds && in_array($snapshot->getDateId(), $xmlAvailableDateIds, true)) {
continue;
}
++$processed;
$dateId = $snapshot->getDateId(); $dateId = $snapshot->getDateId();
$travel = $this->deserializeTravelFromSnapshot($snapshot); $travel = $this->deserializeTravelFromSnapshot($snapshot);
if (null === $travel) { if (null === $travel) {
@@ -237,7 +243,7 @@ class TravelSnapshotService
} }
return [ return [
'processed' => count($candidates), 'processed' => $processed,
'updated' => $updated, 'updated' => $updated,
'failed' => $failed, 'failed' => $failed,
]; ];
@@ -408,6 +408,25 @@ class TravelSnapshotServiceTest extends TestCase
$this->assertSame(['processed' => 1, 'updated' => 0, 'failed' => 1], $result); $this->assertSame(['processed' => 1, 'updated' => 0, 'failed' => 1], $result);
} }
public function testRefreshSkipsSnapshotsWithXmlAvailable(): void
{
$payload = '{"id":100}';
$snapshot = new TravelSnapshot(100, 200, $payload, hash('sha256', $payload));
$this->snapshotRepository
->expects($this->once())
->method('findRefreshCandidates')
->willReturn([$snapshot]);
$this->apiClient
->expects($this->never())
->method('getAvailabilitiesExtended');
$result = $this->service->refreshExtendedSnapshots(500, false, 360, [100]);
$this->assertSame(['processed' => 0, 'updated' => 0, 'failed' => 0], $result);
}
public function testGenerateMappingBuildsCorrectStructure(): void public function testGenerateMappingBuildsCorrectStructure(): void
{ {
$hotel = new Hotel(); $hotel = new Hotel();