refactor: track import progress per film instead of per batch

Replace batch-level progress (processedBatches/totalBatches) with
film-level progress (processedFilms/totalFilms) for smoother UI updates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
thibaud-leclere
2026-04-01 19:30:15 +02:00
parent 8c73a22eff
commit 369893a77e
7 changed files with 70 additions and 62 deletions

View File

@@ -56,11 +56,11 @@ export default class extends Controller {
this.importBtnTarget.disabled = true;
this.importBtnTarget.textContent = 'Import en cours\u2026';
const progress = data.totalBatches > 0
? Math.round((data.processedBatches / data.totalBatches) * 100)
const progress = data.totalFilms > 0
? Math.round((data.processedFilms / data.totalFilms) * 100)
: 0;
this._setStatus(`${progress}% — ${data.totalFilms} films`, 'active');
this._setStatus(`${progress}% — ${data.processedFilms}/${data.totalFilms} films`, 'active');
}
_showCompleted(data) {

View File

@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20260401000002 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add processed_films column to import table';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE import ADD processed_films INT NOT NULL DEFAULT 0');
$this->addSql('ALTER TABLE import DROP COLUMN total_batches');
$this->addSql('ALTER TABLE import DROP COLUMN processed_batches');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE import DROP COLUMN processed_films');
$this->addSql('ALTER TABLE import ADD total_batches INT NOT NULL DEFAULT 0');
$this->addSql('ALTER TABLE import ADD processed_batches INT NOT NULL DEFAULT 0');
}
}

View File

@@ -37,9 +37,8 @@ class ImportController extends AbstractController
'id' => $import->getId(),
'status' => $import->getStatus(),
'totalFilms' => $import->getTotalFilms(),
'processedFilms' => $import->getProcessedFilms(),
'failedFilms' => $import->getFailedFilms(),
'processedBatches' => $import->getProcessedBatches(),
'totalBatches' => $import->getTotalBatches(),
]);
}

View File

@@ -30,15 +30,12 @@ class Import
#[ORM\Column(length: 20)]
private string $status = self::STATUS_PENDING;
#[ORM\Column]
private int $totalBatches = 0;
#[ORM\Column]
private int $processedBatches = 0;
#[ORM\Column]
private int $totalFilms = 0;
#[ORM\Column]
private int $processedFilms = 0;
#[ORM\Column]
private int $failedFilms = 0;
@@ -91,25 +88,14 @@ class Import
return $this;
}
public function getTotalBatches(): int
public function getProcessedFilms(): int
{
return $this->totalBatches;
return $this->processedFilms;
}
public function setTotalBatches(int $totalBatches): static
public function setProcessedFilms(int $processedFilms): static
{
$this->totalBatches = $totalBatches;
return $this;
}
public function getProcessedBatches(): int
{
return $this->processedBatches;
}
public function setProcessedBatches(int $processedBatches): static
{
$this->processedBatches = $processedBatches;
$this->processedFilms = $processedFilms;
return $this;
}

View File

@@ -54,12 +54,9 @@ readonly class ImportFilmsBatchMessageHandler
$movie = $this->filmImporter->importFromLtbxdMovie($ltbxdMovie);
if (!$movie) {
$this->importRepository->incrementFailedFilms($import);
continue;
}
} else {
$this->actorSyncer->syncActorsForMovie($movie);
// Import awards for actors of this movie
foreach ($movie->getActors() as $role) {
$this->awardImporter->importForActor($role->getActor());
}
@@ -77,6 +74,7 @@ readonly class ImportFilmsBatchMessageHandler
}
$this->em->flush();
}
} catch (\Throwable $e) {
$this->logger->warning('Failed to import film', [
'film' => $ltbxdMovie->getName(),
@@ -86,19 +84,16 @@ readonly class ImportFilmsBatchMessageHandler
$this->importRepository->incrementFailedFilms($import);
}
$processedFilms = $this->importRepository->incrementProcessedFilms($import);
$this->em->clear();
$import = $this->em->getRepository(Import::class)->find($importId);
}
$processedBatches = $this->importRepository->incrementProcessedBatches($import);
if ($processedBatches >= $import->getTotalBatches()) {
// Refresh the entity to get updated failedFilms from DB
$this->em->refresh($import);
if ($processedFilms >= $import->getTotalFilms()) {
$import->setStatus(Import::STATUS_COMPLETED);
$import->setCompletedAt(new \DateTimeImmutable());
$this->em->flush();
}
}
}
}

View File

@@ -49,10 +49,8 @@ readonly class ProcessImportMessageHandler
}
$totalFilms = count($ltbxdMovies);
$totalBatches = (int) ceil($totalFilms / self::BATCH_SIZE);
$import->setTotalFilms($totalFilms);
$import->setTotalBatches($totalBatches);
$import->setStatus(Import::STATUS_PROCESSING);
$this->em->flush();

View File

@@ -18,10 +18,10 @@ class ImportRepository extends ServiceEntityRepository
parent::__construct($registry, Import::class);
}
public function incrementProcessedBatches(Import $import): int
public function incrementProcessedFilms(Import $import): int
{
return (int) $this->getEntityManager()->getConnection()->fetchOne(
'UPDATE import SET processed_batches = processed_batches + 1 WHERE id = :id RETURNING processed_batches',
'UPDATE import SET processed_films = processed_films + 1 WHERE id = :id RETURNING processed_films',
['id' => $import->getId()]
);
}