feat: refresh existing snapshots from XML after sync
This commit is contained in:
@@ -9,6 +9,7 @@ use App\Service\TravelSnapshotService;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Command\LockableTrait;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
@@ -26,6 +27,8 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
*/
|
||||
class BpnRefreshTravelSnapshotCommand extends Command
|
||||
{
|
||||
use LockableTrait;
|
||||
|
||||
public function __construct(
|
||||
private readonly TravelSnapshotService $snapshotService,
|
||||
private readonly LoggerInterface $logger,
|
||||
@@ -52,19 +55,28 @@ class BpnRefreshTravelSnapshotCommand extends Command
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
if (false === $this->lock('bpn_xml_sync')) {
|
||||
$this->logger->info('Snapshot refresh skipped: xml-sync is running');
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
$limit = (int) $input->getOption('limit');
|
||||
$force = true === $input->getOption('force');
|
||||
$refreshAfterMinutes = (int) $input->getOption('refresh-after');
|
||||
|
||||
$xmlDateIds = [];
|
||||
$xmlFileMap = null;
|
||||
try {
|
||||
$xmlDateIds = array_keys($this->travelLoader->generateFilesMap());
|
||||
$xmlFileMap = $this->travelLoader->generateFilesMap();
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->warning('Failed to load XML files map for snapshot refresh filtering; refreshing all snapshots', [
|
||||
$this->logger->warning('Failed to load XML files map for snapshot refresh filtering; skipping all candidates', [
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
|
||||
// Phase 2 — enrich non-XML-backed snapshots via extended-availability API
|
||||
$xmlDateIds = null !== $xmlFileMap ? array_keys($xmlFileMap) : null;
|
||||
$result = $this->snapshotService->refreshExtendedSnapshots($limit, $force, $refreshAfterMinutes, $xmlDateIds);
|
||||
|
||||
$io->success(sprintf(
|
||||
|
||||
@@ -5,6 +5,8 @@ declare(strict_types=1);
|
||||
namespace App\Command;
|
||||
|
||||
use App\BusProNet\Model\XmlExportInfo;
|
||||
use App\BusProNet\XmlLoader\TravelLoader;
|
||||
use App\Service\TravelDataService;
|
||||
use League\Flysystem\FilesystemException;
|
||||
use League\Flysystem\FilesystemOperator;
|
||||
use League\Flysystem\StorageAttributes;
|
||||
@@ -38,6 +40,8 @@ class BpnXmlSyncCommand extends Command
|
||||
private readonly FilesystemOperator $xmlExport,
|
||||
private readonly CacheInterface $cache,
|
||||
private readonly LoggerInterface $logger,
|
||||
private readonly TravelLoader $travelLoader,
|
||||
private readonly TravelDataService $travelDataService,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
@@ -53,7 +57,7 @@ class BpnXmlSyncCommand extends Command
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
if (false === $this->lock()) {
|
||||
if (false === $this->lock('bpn_xml_sync')) {
|
||||
$io->warning('Sync is already running in another process');
|
||||
$this->logger->info('XML sync skipped: another instance is running');
|
||||
|
||||
@@ -115,13 +119,38 @@ class BpnXmlSyncCommand extends Command
|
||||
}
|
||||
|
||||
$this->invalidateCaches();
|
||||
$io->text(sprintf('Invalidated %d cache keys', count(self::CACHE_KEYS_TO_INVALIDATE)));
|
||||
$io->info(sprintf('Invalidated %d cache keys', count(self::CACHE_KEYS_TO_INVALIDATE)));
|
||||
|
||||
$io->success(sprintf(
|
||||
'Sync complete: %d files updated, %d files deleted',
|
||||
$syncResult['updated'],
|
||||
$syncResult['deleted']
|
||||
));
|
||||
$io->section('Refreshing snapshots');
|
||||
|
||||
$xmlFileMap = null;
|
||||
$snapshotResult = null;
|
||||
try {
|
||||
$xmlFileMap = $this->travelLoader->generateFilesMap();
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->warning('Failed to generate XML file map after sync; snapshot refresh skipped', [
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
|
||||
if (null !== $xmlFileMap) {
|
||||
$total = array_sum(array_map(fn ($entry) => count($entry['hotels']), $xmlFileMap));
|
||||
$io->progressStart($total);
|
||||
|
||||
$snapshotResult = $this->travelDataService->syncSnapshotsFromXml(
|
||||
$xmlFileMap,
|
||||
function () use ($io): void { $io->progressAdvance(); },
|
||||
);
|
||||
|
||||
$io->progressFinish();
|
||||
$this->logger->info('Travel snapshot XML sync triggered by xml-sync command', $snapshotResult);
|
||||
}
|
||||
|
||||
$successMessage = sprintf('Sync complete: %d files updated, %d files deleted', $syncResult['updated'], $syncResult['deleted']);
|
||||
if (null !== $snapshotResult) {
|
||||
$successMessage .= sprintf(', snapshots: %d processed, %d failed', $snapshotResult['processed'], $snapshotResult['failed']);
|
||||
}
|
||||
$io->success($successMessage);
|
||||
$this->logger->info('XML sync completed', [
|
||||
'files_updated' => $syncResult['updated'],
|
||||
'files_deleted' => $syncResult['deleted'],
|
||||
|
||||
Reference in New Issue
Block a user