refactor: embed film data directly in batch messages

Avoid re-parsing the entire CSV file in each batch handler by including
the film data in the message payload itself.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
thibaud-leclere
2026-04-01 19:25:45 +02:00
parent 087b063f1f
commit 8c73a22eff
3 changed files with 24 additions and 20 deletions

View File

@@ -6,9 +6,11 @@ namespace App\Message;
readonly class ImportFilmsBatchMessage readonly class ImportFilmsBatchMessage
{ {
/**
* @param list<array{name: string, year: int, ltbxdUri: string, date: string}> $films
*/
public function __construct( public function __construct(
public int $importId, public int $importId,
public int $offset, public array $films,
public int $limit,
) {} ) {}
} }

View File

@@ -6,14 +6,13 @@ namespace App\MessageHandler;
use App\Entity\Import; use App\Entity\Import;
use App\Entity\UserMovie; use App\Entity\UserMovie;
use App\Gateway\LtbxdGateway;
use App\Message\ImportFilmsBatchMessage; use App\Message\ImportFilmsBatchMessage;
use App\Model\Ltbxd\LtbxdMovie;
use App\Repository\ImportRepository; use App\Repository\ImportRepository;
use App\Import\ActorSyncer; use App\Import\ActorSyncer;
use App\Import\AwardImporter; use App\Import\AwardImporter;
use App\Import\FilmImporter; use App\Import\FilmImporter;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use League\Flysystem\FilesystemOperator;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\Messenger\Attribute\AsMessageHandler; use Symfony\Component\Messenger\Attribute\AsMessageHandler;
@@ -22,8 +21,6 @@ readonly class ImportFilmsBatchMessageHandler
{ {
public function __construct( public function __construct(
private EntityManagerInterface $em, private EntityManagerInterface $em,
private FilesystemOperator $defaultStorage,
private LtbxdGateway $ltbxdGateway,
private FilmImporter $filmImporter, private FilmImporter $filmImporter,
private ActorSyncer $actorSyncer, private ActorSyncer $actorSyncer,
private ImportRepository $importRepository, private ImportRepository $importRepository,
@@ -40,17 +37,15 @@ readonly class ImportFilmsBatchMessageHandler
return; return;
} }
$csvContent = $this->defaultStorage->read($import->getFilePath()); $batch = array_map(
$tmpFile = tempnam(sys_get_temp_dir(), 'import_'); fn (array $film) => new LtbxdMovie(
file_put_contents($tmpFile, $csvContent); date: new \DateTime($film['date']),
name: $film['name'],
try { year: $film['year'],
$ltbxdMovies = $this->ltbxdGateway->parseFileFromPath($tmpFile); ltbxdUri: $film['ltbxdUri'],
} finally { ),
unlink($tmpFile); $message->films,
} );
$batch = array_slice($ltbxdMovies, $message->offset, $message->limit);
$userId = $import->getUser()->getId(); $userId = $import->getUser()->getId();
$importId = $import->getId(); $importId = $import->getId();

View File

@@ -56,11 +56,18 @@ readonly class ProcessImportMessageHandler
$import->setStatus(Import::STATUS_PROCESSING); $import->setStatus(Import::STATUS_PROCESSING);
$this->em->flush(); $this->em->flush();
for ($i = 0; $i < $totalBatches; $i++) { $batches = array_chunk($ltbxdMovies, self::BATCH_SIZE);
foreach ($batches as $batch) {
$films = array_map(fn ($movie) => [
'name' => $movie->getName(),
'year' => $movie->getYear(),
'ltbxdUri' => $movie->getLtbxdUri(),
'date' => $movie->getDate()->format('Y-m-d'),
], $batch);
$this->bus->dispatch(new ImportFilmsBatchMessage( $this->bus->dispatch(new ImportFilmsBatchMessage(
importId: $import->getId(), importId: $import->getId(),
offset: $i * self::BATCH_SIZE, films: $films,
limit: self::BATCH_SIZE,
)); ));
} }
} catch (\Throwable $e) { } catch (\Throwable $e) {