From f637baf7a3076d4adef17a355b4b340a9979e125 Mon Sep 17 00:00:00 2001 From: Priyadi Iman Nurcahyo <1102197+priyadi@users.noreply.github.com> Date: Tue, 16 Jul 2024 16:06:01 +0700 Subject: [PATCH] refactor: batch (#123) * refactor: batch * namespace reorg * add timing * restore metrics * cosmetic * revert composer.json --- .../rekapager-core/src/Batch/BatchProcess.php | 22 +- .../src/Batch/BatchProcessorDecorator.php | 20 +- .../src/Batch/BatchProcessorInterface.php | 10 + .../src/Batch/Event/AfterProcessEvent.php | 20 +- .../src/Batch/Event/BeforeProcessEvent.php | 18 ++ .../src/Batch/Event/InterruptEvent.php | 18 ++ .../src/{ => Batch}/BatchCommand.php | 5 +- .../src/Batch/Internal/BatchTimer.php | 89 ++++++++ .../CommandBatchProcessorDecorator.php | 209 ++++++++++++++++++ .../src/{ => Batch}/SimpleBatchCommand.php | 2 +- .../src/BatchProcessorDecorator.php | 149 ------------- .../App/BatchProcessor/PostBatchProcessor.php | 2 +- tests/src/App/Command/AppBatchCommand.php | 2 +- .../src/App/Command/AppSimpleBatchCommand.php | 4 +- 14 files changed, 394 insertions(+), 176 deletions(-) rename packages/rekapager-symfony-bridge/src/{ => Batch}/BatchCommand.php (96%) create mode 100644 packages/rekapager-symfony-bridge/src/Batch/Internal/BatchTimer.php create mode 100644 packages/rekapager-symfony-bridge/src/Batch/Internal/CommandBatchProcessorDecorator.php rename packages/rekapager-symfony-bridge/src/{ => Batch}/SimpleBatchCommand.php (96%) delete mode 100644 packages/rekapager-symfony-bridge/src/BatchProcessorDecorator.php diff --git a/packages/rekapager-core/src/Batch/BatchProcess.php b/packages/rekapager-core/src/Batch/BatchProcess.php index 9e55521..aa5d19e 100644 --- a/packages/rekapager-core/src/Batch/BatchProcess.php +++ b/packages/rekapager-core/src/Batch/BatchProcess.php @@ -60,6 +60,8 @@ final public function process( ?string $resume = null, ?int $pageSize = null ): void { + // determine start page identifier + if ($resume !== null) { $startPageIdentifier = $this->pageableIdentifierResolver ->decode($this->pageable, $resume); @@ -67,28 +69,28 @@ final public function process( $startPageIdentifier = null; } + // prepare pages + $itemsPerPage = $pageSize ?? $this->batchProcessor->getItemsPerPage(); $pageable = $this->pageable->withItemsPerPage($itemsPerPage); + $pages = $pageable->getPages($startPageIdentifier); + + // emit event $beforeProcessEvent = new BeforeProcessEvent( + pageable: $pageable, startPageIdentifier: $resume, ); $this->batchProcessor->beforeProcess($beforeProcessEvent); - $pages = $pageable->getPages($startPageIdentifier); - - $numOfPages = 0; - $numOfItems = 0; - foreach ($pages as $page) { - $numOfPages++; - $pageIdentifier = $page->getPageIdentifier(); $pageIdentifierString = $this->pageableIdentifierResolver->encode($pageIdentifier); if ($this->stopFlag) { $interruptEvent = new InterruptEvent( + pageable: $pageable, nextPageIdentifier: $pageIdentifierString, ); @@ -105,8 +107,6 @@ final public function process( $this->batchProcessor->beforePage($beforePageEvent); foreach ($page as $key => $item) { - $numOfItems++; - $itemEvent = new ItemEvent( key: $key, item: $item, @@ -122,7 +122,9 @@ final public function process( $this->batchProcessor->afterPage($afterPageEvent); } - $afterProcessEvent = new AfterProcessEvent(); + $afterProcessEvent = new AfterProcessEvent( + pageable: $pageable, + ); $this->batchProcessor->afterProcess($afterProcessEvent); } diff --git a/packages/rekapager-core/src/Batch/BatchProcessorDecorator.php b/packages/rekapager-core/src/Batch/BatchProcessorDecorator.php index db3b2f8..964038c 100644 --- a/packages/rekapager-core/src/Batch/BatchProcessorDecorator.php +++ b/packages/rekapager-core/src/Batch/BatchProcessorDecorator.php @@ -28,42 +28,44 @@ abstract class BatchProcessorDecorator implements BatchProcessorInterface { /** - * @return BatchProcessorInterface + * @param BatchProcessorInterface $decorated */ - abstract protected function getDecorated(): BatchProcessorInterface; + public function __construct(private BatchProcessorInterface $decorated) + { + } public function processItem(ItemEvent $itemEvent): void { - $this->getDecorated()->processItem($itemEvent); + $this->decorated->processItem($itemEvent); } public function getItemsPerPage(): int { - return $this->getDecorated()->getItemsPerPage(); + return $this->decorated->getItemsPerPage(); } public function beforeProcess(BeforeProcessEvent $event): void { - $this->getDecorated()->beforeProcess($event); + $this->decorated->beforeProcess($event); } public function afterProcess(AfterProcessEvent $event): void { - $this->getDecorated()->afterProcess($event); + $this->decorated->afterProcess($event); } public function beforePage(BeforePageEvent $event): void { - $this->getDecorated()->beforePage($event); + $this->decorated->beforePage($event); } public function afterPage(AfterPageEvent $event): void { - $this->getDecorated()->afterPage($event); + $this->decorated->afterPage($event); } public function onInterrupt(InterruptEvent $event): void { - $this->getDecorated()->onInterrupt($event); + $this->decorated->onInterrupt($event); } } diff --git a/packages/rekapager-core/src/Batch/BatchProcessorInterface.php b/packages/rekapager-core/src/Batch/BatchProcessorInterface.php index 847a4e2..f29dea7 100644 --- a/packages/rekapager-core/src/Batch/BatchProcessorInterface.php +++ b/packages/rekapager-core/src/Batch/BatchProcessorInterface.php @@ -36,7 +36,14 @@ public function processItem(ItemEvent $itemEvent): void; */ public function getItemsPerPage(): int; + /** + * @param BeforeProcessEvent $event + */ public function beforeProcess(BeforeProcessEvent $event): void; + + /** + * @param AfterProcessEvent $event + */ public function afterProcess(AfterProcessEvent $event): void; /** @@ -49,5 +56,8 @@ public function beforePage(BeforePageEvent $event): void; */ public function afterPage(AfterPageEvent $event): void; + /** + * @param InterruptEvent $event + */ public function onInterrupt(InterruptEvent $event): void; } diff --git a/packages/rekapager-core/src/Batch/Event/AfterProcessEvent.php b/packages/rekapager-core/src/Batch/Event/AfterProcessEvent.php index 11b8c66..cc49859 100644 --- a/packages/rekapager-core/src/Batch/Event/AfterProcessEvent.php +++ b/packages/rekapager-core/src/Batch/Event/AfterProcessEvent.php @@ -13,9 +13,27 @@ namespace Rekalogika\Rekapager\Batch\Event; +use Rekalogika\Contracts\Rekapager\PageableInterface; + +/** + * @template TKey of array-key + * @template T + */ final class AfterProcessEvent { - public function __construct() + /** + * @param PageableInterface $pageable + */ + public function __construct( + private readonly PageableInterface $pageable, + ) { + } + + /** + * @return PageableInterface + */ + public function getPageable(): PageableInterface { + return $this->pageable; } } diff --git a/packages/rekapager-core/src/Batch/Event/BeforeProcessEvent.php b/packages/rekapager-core/src/Batch/Event/BeforeProcessEvent.php index cbd6a13..8eb61a6 100644 --- a/packages/rekapager-core/src/Batch/Event/BeforeProcessEvent.php +++ b/packages/rekapager-core/src/Batch/Event/BeforeProcessEvent.php @@ -13,9 +13,19 @@ namespace Rekalogika\Rekapager\Batch\Event; +use Rekalogika\Contracts\Rekapager\PageableInterface; + +/** + * @template TKey of array-key + * @template T + */ final class BeforeProcessEvent { + /** + * @param PageableInterface $pageable + */ public function __construct( + private readonly PageableInterface $pageable, private readonly ?string $startPageIdentifier, ) { } @@ -24,4 +34,12 @@ public function getStartPageIdentifier(): ?string { return $this->startPageIdentifier; } + + /** + * @return PageableInterface + */ + public function getPageable(): PageableInterface + { + return $this->pageable; + } } diff --git a/packages/rekapager-core/src/Batch/Event/InterruptEvent.php b/packages/rekapager-core/src/Batch/Event/InterruptEvent.php index 10bb76c..ec34092 100644 --- a/packages/rekapager-core/src/Batch/Event/InterruptEvent.php +++ b/packages/rekapager-core/src/Batch/Event/InterruptEvent.php @@ -13,13 +13,31 @@ namespace Rekalogika\Rekapager\Batch\Event; +use Rekalogika\Contracts\Rekapager\PageableInterface; + +/** + * @template TKey of array-key + * @template T + */ final class InterruptEvent { + /** + * @param PageableInterface $pageable + */ public function __construct( + private readonly PageableInterface $pageable, private readonly ?string $nextPageIdentifier, ) { } + /** + * @return PageableInterface + */ + public function getPageable(): PageableInterface + { + return $this->pageable; + } + public function getNextPageIdentifier(): ?string { return $this->nextPageIdentifier; diff --git a/packages/rekapager-symfony-bridge/src/BatchCommand.php b/packages/rekapager-symfony-bridge/src/Batch/BatchCommand.php similarity index 96% rename from packages/rekapager-symfony-bridge/src/BatchCommand.php rename to packages/rekapager-symfony-bridge/src/Batch/BatchCommand.php index 4adbf07..ade55c0 100644 --- a/packages/rekapager-symfony-bridge/src/BatchCommand.php +++ b/packages/rekapager-symfony-bridge/src/Batch/BatchCommand.php @@ -11,7 +11,7 @@ * that was distributed with this source code. */ -namespace Rekalogika\Rekapager\Symfony; +namespace Rekalogika\Rekapager\Symfony\Batch; use Rekalogika\Contracts\Rekapager\Exception\InvalidArgumentException; use Rekalogika\Contracts\Rekapager\Exception\LogicException; @@ -20,6 +20,7 @@ use Rekalogika\Rekapager\Batch\BatchProcess; use Rekalogika\Rekapager\Batch\BatchProcessFactoryInterface; use Rekalogika\Rekapager\Batch\BatchProcessorInterface; +use Rekalogika\Rekapager\Symfony\Batch\Internal\CommandBatchProcessorDecorator; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Command\SignalableCommandInterface; use Symfony\Component\Console\Input\InputInterface; @@ -112,7 +113,7 @@ final protected function execute(InputInterface $input, OutputInterface $output) $pageable = $this->getPageable($input, $output); $this->io = new SymfonyStyle($input, $output); - $batchProcessor = new BatchProcessorDecorator( + $batchProcessor = new CommandBatchProcessorDecorator( decorated: $this->getBatchProcessor(), io: $this->io, progressFile: $progressFile, diff --git a/packages/rekapager-symfony-bridge/src/Batch/Internal/BatchTimer.php b/packages/rekapager-symfony-bridge/src/Batch/Internal/BatchTimer.php new file mode 100644 index 0000000..ac6de47 --- /dev/null +++ b/packages/rekapager-symfony-bridge/src/Batch/Internal/BatchTimer.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE file + * that was distributed with this source code. + */ + +namespace Rekalogika\Rekapager\Symfony\Batch\Internal; + +use Rekalogika\Contracts\Rekapager\Exception\LogicException; + +/** + * @internal + */ +class BatchTimer +{ + public const TIMER_PROCESS = 'process'; + public const TIMER_PAGE = 'page'; + public const TIMER_ITEM = 'item'; + public const TIMER_DISPLAY = 'display'; + + /** + * @var array + */ + private array $timers = []; + + /** + * @param BatchTimer::TIMER_* $timer + */ + public function start(string $timer): void + { + if (isset($this->timers[$timer])) { + throw new LogicException(sprintf('Timer "%s" is already started.', $timer)); + } + + $this->timers[$timer] = hrtime(true); + } + + /** + * @param BatchTimer::TIMER_* $timer + */ + public function stop(string $timer): float + { + $result = $this->getDuration($timer); + + if ($result === null) { + throw new LogicException(sprintf('Timer "%s" has not been started yet.', $timer)); + } + + $this->reset($timer); + + return $result; + } + + /** + * @param BatchTimer::TIMER_* $timer + */ + public function restart(string $timer): void + { + $this->reset($timer); + $this->start($timer); + } + + /** + * @param BatchTimer::TIMER_* $timer + */ + public function reset(string $timer): void + { + unset($this->timers[$timer]); + } + + /** + * @param BatchTimer::TIMER_* $timer + */ + public function getDuration(string $timer): ?float + { + if (!isset($this->timers[$timer])) { + return null; + } + + return (hrtime(true) - $this->timers[$timer]) / 1e9; + } +} diff --git a/packages/rekapager-symfony-bridge/src/Batch/Internal/CommandBatchProcessorDecorator.php b/packages/rekapager-symfony-bridge/src/Batch/Internal/CommandBatchProcessorDecorator.php new file mode 100644 index 0000000..863f7c5 --- /dev/null +++ b/packages/rekapager-symfony-bridge/src/Batch/Internal/CommandBatchProcessorDecorator.php @@ -0,0 +1,209 @@ + + * + * For the full copyright and license information, please view the LICENSE file + * that was distributed with this source code. + */ + +namespace Rekalogika\Rekapager\Symfony\Batch\Internal; + +use Rekalogika\Rekapager\Batch\BatchProcessorDecorator; +use Rekalogika\Rekapager\Batch\BatchProcessorInterface; +use Rekalogika\Rekapager\Batch\Event\AfterPageEvent; +use Rekalogika\Rekapager\Batch\Event\AfterProcessEvent; +use Rekalogika\Rekapager\Batch\Event\BeforePageEvent; +use Rekalogika\Rekapager\Batch\Event\BeforeProcessEvent; +use Rekalogika\Rekapager\Batch\Event\InterruptEvent; +use Rekalogika\Rekapager\Batch\Event\ItemEvent; +use Symfony\Component\Console\Helper\Helper; +use Symfony\Component\Console\Helper\ProgressIndicator; +use Symfony\Component\Console\Style\SymfonyStyle; + +/** + * @template TKey of array-key + * @template T + * @extends BatchProcessorDecorator + * @internal + */ +class CommandBatchProcessorDecorator extends BatchProcessorDecorator +{ + private readonly BatchTimer $timer; + private int $pageNumber = 0; + private int $itemNumber = 0; + private ?\DateTimeInterface $startTime = null; + private readonly ProgressIndicator $progressIndicator; + + /** + * @param BatchProcessorInterface $decorated + */ + public function __construct( + private readonly BatchProcessorInterface $decorated, + private readonly SymfonyStyle $io, + private readonly ?string $progressFile, + ) { + parent::__construct($decorated); + + $this->timer = new BatchTimer(); + $this->progressIndicator = new ProgressIndicator($this->io, 'very_verbose'); + } + + private static function formatTime(\DateTimeInterface $time): string + { + return $time->format('Y-m-d H:i:s T'); + } + + public function beforeProcess(BeforeProcessEvent $event): void + { + $this->startTime = new \DateTimeImmutable(); + $this->timer->start(BatchTimer::TIMER_DISPLAY); + $this->timer->start(BatchTimer::TIMER_PROCESS); + + $this->io->success('Starting batch process'); + + $this->io->definitionList( + ['Start time' => self::formatTime($this->startTime)], + ['Start page' => $event->getStartPageIdentifier() ?? '(first page)'], + ['Progress file' => $this->progressFile ?? '(not used)'], + ['Items per page' => $event->getPageable()->getItemsPerPage()], + ['Total pages' => $event->getPageable()->getTotalPages() ?? '(unknown)'], + ['Total items' => $event->getPageable()->getTotalItems() ?? '(unknown)'], + ); + + $this->decorated->beforeProcess($event); + } + + public function afterProcess(AfterProcessEvent $event): void + { + $this->decorated->afterProcess($event); + + if ($this->progressFile !== null && file_exists($this->progressFile)) { + unlink($this->progressFile); + } + + $this->io->success('Batch process completed'); + $this->showStats($event); + } + + public function beforePage(BeforePageEvent $event): void + { + $this->pageNumber++; + // $this->timer->start(BatchTimer::TIMER_PAGE); + + if ($this->progressFile !== null) { + file_put_contents($this->progressFile, $event->getEncodedPageIdentifier()); + } + + $this->progressIndicator->start(sprintf( + 'Page %s, identifier %s', + $event->getPage()->getPageNumber() ?? '(unknown)', + $event->getEncodedPageIdentifier(), + )); + + $this->decorated->beforePage($event); + } + + public function afterPage(AfterPageEvent $event): void + { + $this->decorated->afterPage($event); + // $pageDuration = $this->timer->stop(BatchTimer::TIMER_PAGE); + + $this->progressIndicator->finish(sprintf( + 'Page %s, identifier %s', + $event->getPage()->getPageNumber() ?? '(unknown)', + $event->getEncodedPageIdentifier(), + )); + + $displayDuration = $this->timer->getDuration(BatchTimer::TIMER_DISPLAY); + + if ($displayDuration > 15) { + $this->timer->restart(BatchTimer::TIMER_DISPLAY); + $this->showStats($event); + } + } + + public function processItem(ItemEvent $itemEvent): void + { + $this->itemNumber++; + + $sinceLast = $this->timer->getDuration(BatchTimer::TIMER_ITEM); + + if ($sinceLast === null || $sinceLast > 1) { + $this->timer->restart(BatchTimer::TIMER_ITEM); + $this->progressIndicator->advance(); + } + + $this->decorated->processItem($itemEvent); + } + + public function onInterrupt(InterruptEvent $event): void + { + $this->decorated->onInterrupt($event); + + $nextPageIdentifier = $event->getNextPageIdentifier(); + + if ($this->progressFile !== null) { + $this->io->warning(sprintf( + 'Batch process interrupted. To resume, use the argument "-f %s"', + $this->progressFile + )); + } elseif ($nextPageIdentifier !== null) { + $this->io->warning(sprintf( + 'Batch process interrupted. To resume, use the argument "-r %s"', + $nextPageIdentifier + )); + } else { + $this->io->error('Batch process interrupted, but there does not seem to be a next page identifier for you to resume'); + } + + $this->showStats($event); + } + + /** + * @param AfterPageEvent|AfterProcessEvent|InterruptEvent $event + * @return void + */ + private function showStats(AfterPageEvent|AfterProcessEvent|InterruptEvent $event): void + { + if ($event instanceof AfterPageEvent) { + $this->io->writeln(''); + } + + $processDuration = $this->timer->getDuration(BatchTimer::TIMER_PROCESS); + + $stats = []; + + if ($this->startTime !== null) { + $stats[] = ['Start time' => self::formatTime($this->startTime)]; + } + + if ($event instanceof AfterPageEvent) { + $stats[] = ['Current time' => self::formatTime(new \DateTimeImmutable())]; + } else { + $stats[] = ['End time' => self::formatTime(new \DateTimeImmutable())]; + } + + if ($processDuration !== null) { + $stats[] = ['Time elapsed' => Helper::formatTime($processDuration)]; + } + + $stats = [ + ...$stats, + ['Page processed' => $this->pageNumber], + ['Item processed' => $this->itemNumber], + ['Memory usage' => Helper::formatMemory(memory_get_usage(true))], + ]; + + if ($processDuration !== null) { + $stats[] = ['Pages/minute' => round($this->pageNumber / $processDuration * 60, 2)]; + $stats[] = ['Items/minute' => round($this->itemNumber / $processDuration * 60, 2)]; + } + + $this->io->definitionList(...$stats); + } +} diff --git a/packages/rekapager-symfony-bridge/src/SimpleBatchCommand.php b/packages/rekapager-symfony-bridge/src/Batch/SimpleBatchCommand.php similarity index 96% rename from packages/rekapager-symfony-bridge/src/SimpleBatchCommand.php rename to packages/rekapager-symfony-bridge/src/Batch/SimpleBatchCommand.php index eac2fc8..b3bf7cb 100644 --- a/packages/rekapager-symfony-bridge/src/SimpleBatchCommand.php +++ b/packages/rekapager-symfony-bridge/src/Batch/SimpleBatchCommand.php @@ -11,7 +11,7 @@ * that was distributed with this source code. */ -namespace Rekalogika\Rekapager\Symfony; +namespace Rekalogika\Rekapager\Symfony\Batch; use Rekalogika\Rekapager\Batch\BatchProcessorInterface; use Rekalogika\Rekapager\Batch\Event\AfterPageEvent; diff --git a/packages/rekapager-symfony-bridge/src/BatchProcessorDecorator.php b/packages/rekapager-symfony-bridge/src/BatchProcessorDecorator.php deleted file mode 100644 index 095e8b5..0000000 --- a/packages/rekapager-symfony-bridge/src/BatchProcessorDecorator.php +++ /dev/null @@ -1,149 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE file - * that was distributed with this source code. - */ - -namespace Rekalogika\Rekapager\Symfony; - -use Rekalogika\Rekapager\Batch\BatchProcessorDecorator as CoreBatchProcessorDecorator; -use Rekalogika\Rekapager\Batch\BatchProcessorInterface; -use Rekalogika\Rekapager\Batch\Event\AfterPageEvent; -use Rekalogika\Rekapager\Batch\Event\AfterProcessEvent; -use Rekalogika\Rekapager\Batch\Event\BeforePageEvent; -use Rekalogika\Rekapager\Batch\Event\BeforeProcessEvent; -use Rekalogika\Rekapager\Batch\Event\InterruptEvent; -use Symfony\Component\Console\Helper\Helper; -use Symfony\Component\Console\Style\SymfonyStyle; - -/** - * @template TKey of array-key - * @template T - * @extends CoreBatchProcessorDecorator - */ -class BatchProcessorDecorator extends CoreBatchProcessorDecorator -{ - private float $pageStart = 0; - private float $lastStat = 0; - - /** - * @param BatchProcessorInterface $decorated - */ - public function __construct( - private BatchProcessorInterface $decorated, - private SymfonyStyle $io, - private ?string $progressFile, - ) { - } - - protected function getDecorated(): BatchProcessorInterface - { - return $this->decorated; - } - - public function beforeProcess(BeforeProcessEvent $event): void - { - $this->lastStat = microtime(true); - - $this->io->success('Starting batch process'); - - $this->io->definitionList( - ['Start page' => $event->getStartPageIdentifier() ?? '(first page)'], - ['Progress file' => $this->progressFile ?? '(not used)'], - ['Items per page' => $this->getItemsPerPage()], - // ['Total pages' => $event->getTotalPages() ?? '(unknown)'], - // ['Total items' => $event->getTotalItems() ?? '(unknown)'], - ); - - $this->decorated->beforeProcess($event); - } - - public function afterProcess(AfterProcessEvent $event): void - { - $this->decorated->afterProcess($event); - - if ($this->progressFile !== null && file_exists($this->progressFile)) { - unlink($this->progressFile); - } - - $this->io->success('Batch process completed'); - $this->showStats($event); - } - - public function beforePage(BeforePageEvent $event): void - { - $this->pageStart = microtime(true); - - if ($this->progressFile !== null) { - file_put_contents($this->progressFile, $event->getEncodedPageIdentifier()); - } - - $this->decorated->beforePage($event); - } - - public function afterPage(AfterPageEvent $event): void - { - $this->decorated->afterPage($event); - - $duration = microtime(true) - $this->pageStart; - - $this->io->writeln(sprintf( - 'Page processed, page number: %s, identifier: %s, duration: %s', - $event->getPage()->getPageNumber() ?? '(unknown)', - $event->getEncodedPageIdentifier(), - Helper::formatTime($duration) - )); - - if (microtime(true) - $this->lastStat > 15) { - $this->lastStat = microtime(true); - $this->showStats($event); - } - } - - public function onInterrupt(InterruptEvent $event): void - { - $this->decorated->onInterrupt($event); - - $nextPageIdentifier = $event->getNextPageIdentifier(); - - if ($this->progressFile !== null) { - $this->io->warning(sprintf( - 'Batch process interrupted. To resume, use the argument "-f %s"', - $this->progressFile - )); - } elseif ($nextPageIdentifier !== null) { - $this->io->warning(sprintf( - 'Batch process interrupted. To resume, use the argument "-r %s"', - $nextPageIdentifier - )); - } else { - $this->io->error('Batch process interrupted, but there does not seem to be a next page identifier for you to resume'); - } - - $this->showStats($event); - } - - /** - * @param AfterPageEvent|AfterProcessEvent|InterruptEvent $event - * @return void - */ - private function showStats(AfterPageEvent|AfterProcessEvent|InterruptEvent $event): void - { - $this->io->writeln(''); - $this->io->definitionList( - // ['Time elapsed' => Helper::formatTime($event->getProcessDuration())], - ['Memory usage' => Helper::formatMemory(memory_get_usage(true))], - // ['Pages processed' => $event->getPagesProcessed()], - // ['Items processed' => $event->getItemsProcessed()], - // ['Pages/minute' => round($event->getPagesProcessed() / $event->getProcessDuration() * 60, 2)], - // ['Items/minute' => round($event->getItemsProcessed() / $event->getProcessDuration() * 60, 2)], - ); - } -} diff --git a/tests/src/App/BatchProcessor/PostBatchProcessor.php b/tests/src/App/BatchProcessor/PostBatchProcessor.php index 295e8c3..e4eaa43 100644 --- a/tests/src/App/BatchProcessor/PostBatchProcessor.php +++ b/tests/src/App/BatchProcessor/PostBatchProcessor.php @@ -30,7 +30,7 @@ public function __construct(private EntityManagerInterface $entityManager) public function processItem(ItemEvent $itemEvent): void { - usleep(20000); + usleep(50000); } public function afterPage(AfterPageEvent $event): void diff --git a/tests/src/App/Command/AppBatchCommand.php b/tests/src/App/Command/AppBatchCommand.php index 2e3d033..3983436 100644 --- a/tests/src/App/Command/AppBatchCommand.php +++ b/tests/src/App/Command/AppBatchCommand.php @@ -17,7 +17,7 @@ use Rekalogika\Rekapager\Batch\BatchProcessorInterface; use Rekalogika\Rekapager\Doctrine\Collections\SelectableAdapter; use Rekalogika\Rekapager\Keyset\KeysetPageable; -use Rekalogika\Rekapager\Symfony\BatchCommand; +use Rekalogika\Rekapager\Symfony\Batch\BatchCommand; use Rekalogika\Rekapager\Tests\App\BatchProcessor\PostBatchProcessor; use Rekalogika\Rekapager\Tests\App\Entity\Post; use Rekalogika\Rekapager\Tests\App\Repository\PostRepository; diff --git a/tests/src/App/Command/AppSimpleBatchCommand.php b/tests/src/App/Command/AppSimpleBatchCommand.php index 47d98d2..bdd3d59 100644 --- a/tests/src/App/Command/AppSimpleBatchCommand.php +++ b/tests/src/App/Command/AppSimpleBatchCommand.php @@ -19,7 +19,7 @@ use Rekalogika\Rekapager\Batch\Event\ItemEvent; use Rekalogika\Rekapager\Doctrine\Collections\SelectableAdapter; use Rekalogika\Rekapager\Keyset\KeysetPageable; -use Rekalogika\Rekapager\Symfony\SimpleBatchCommand; +use Rekalogika\Rekapager\Symfony\Batch\SimpleBatchCommand; use Rekalogika\Rekapager\Tests\App\Entity\Post; use Rekalogika\Rekapager\Tests\App\Repository\PostRepository; use Symfony\Component\Console\Attribute\AsCommand; @@ -51,7 +51,7 @@ protected function getPageable(InputInterface $input, OutputInterface $output): public function processItem(ItemEvent $itemEvent): void { - usleep(20000); + usleep(50000); } public function afterPage(AfterPageEvent $event): void