Browse Source

bug-fix prewarm cache size

imwald
Silberengel 1 week ago
parent
commit
ff20ae7835
  1. 2
      README.md
  2. 53
      src/Command/PrewarmCommand.php

2
README.md

@ -80,7 +80,7 @@ make prewarm
| `--metadata-limit` | `0` (all authors) | Cap distinct author pubkeys | | `--metadata-limit` | `0` (all authors) | Cap distinct author pubkeys |
| `--metadata-batch` | `50` | Pubkeys per batched Nostr `REQ` | | `--metadata-batch` | `50` | Pubkeys per batched Nostr `REQ` |
| `--comments-max` | `20` | Newest **N** articles (by `createdAt` **DESC**); `0` = all (still bounded by budget) | | `--comments-max` | `20` | Newest **N** articles (by `createdAt` **DESC**); `0` = all (still bounded by budget) |
| `--comments-budget` | `120` | Max wall seconds for the comments phase | | `--comments-budget` | `600` | Max wall seconds for the whole comments phase (Nostr is slow; raise e.g. `1200` if you need more articles in one run) |
| `--magazine-budget` | `30` | Max wall seconds for magazine refresh | | `--magazine-budget` | `30` | Max wall seconds for magazine refresh |
Prewarm clears the PHP **CLI** execution time limit for that run; relay work can be slow. Prewarm clears the PHP **CLI** execution time limit for that run; relay work can be slow.

53
src/Command/PrewarmCommand.php

@ -57,7 +57,7 @@ final class PrewarmCommand extends Command
->addOption('metadata-limit', null, InputOption::VALUE_REQUIRED, 'Max distinct author pubkeys to warm (0 = all)', '0') ->addOption('metadata-limit', null, InputOption::VALUE_REQUIRED, 'Max distinct author pubkeys to warm (0 = all)', '0')
->addOption('metadata-batch', null, InputOption::VALUE_REQUIRED, 'Kind-0 metadata: pubkeys per Nostr REQ (batched)', '50') ->addOption('metadata-batch', null, InputOption::VALUE_REQUIRED, 'Kind-0 metadata: pubkeys per Nostr REQ (batched)', '50')
->addOption('comments-max', null, InputOption::VALUE_REQUIRED, 'Newest N articles to warm comment cache for (0 = all, order: createdAt DESC)', '20') ->addOption('comments-max', null, InputOption::VALUE_REQUIRED, 'Newest N articles to warm comment cache for (0 = all, order: createdAt DESC)', '20')
->addOption('comments-budget', null, InputOption::VALUE_REQUIRED, 'Max seconds for the whole comments phase', '120'); ->addOption('comments-budget', null, InputOption::VALUE_REQUIRED, 'Wall-clock seconds for the whole comments phase (Nostr fetches are slow; a single long thread can exceed a short budget; use 1200+ if 20+ articles)', '600');
} }
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
@ -254,7 +254,9 @@ final class PrewarmCommand extends Command
$maxArticles = (int) $input->getOption('comments-max'); $maxArticles = (int) $input->getOption('comments-max');
$io->section('Comment / interaction cache'); $io->section('Comment / interaction cache');
$deadline = microtime(true) + max(1, (int) $input->getOption('comments-budget')); $commentBudgetSeconds = max(1, (int) $input->getOption('comments-budget'));
$commentPhaseStart = microtime(true);
$deadline = $commentPhaseStart + $commentBudgetSeconds;
$qb = $this->articleRepository->createQueryBuilder('a') $qb = $this->articleRepository->createQueryBuilder('a')
->where('a.slug IS NOT NULL') ->where('a.slug IS NOT NULL')
->andWhere("a.slug != ''") ->andWhere("a.slug != ''")
@ -276,7 +278,10 @@ final class PrewarmCommand extends Command
/** @var Article $article */ /** @var Article $article */
foreach ($articles as $article) { foreach ($articles as $article) {
if (microtime(true) >= $deadline) { if (microtime(true) >= $deadline) {
$io->warning('Comment phase stopped: comments-budget reached.'); $io->warning(sprintf(
'Comment phase stopped: comments-budget reached (%s).',
$this->formatCommentBudgetSecondsPair(microtime(true) - $commentPhaseStart, $commentBudgetSeconds),
));
break; break;
} }
$slug = trim((string) $article->getSlug()); $slug = trim((string) $article->getSlug());
@ -304,15 +309,30 @@ final class PrewarmCommand extends Command
$cBar->advance(1); $cBar->advance(1);
} }
} finally { } finally {
$cBar->finish(); $this->finishPrewarmProgressBarWithoutFillingToMax($cBar, $io);
$io->newLine(2);
} }
} }
$io->success(sprintf('Warmed comment cache for %d of %d article(s).', $w, $articleCount)); $io->success(sprintf(
'Warmed comment cache for %d of %d article(s). Comment phase wall time %s.',
$w,
$articleCount,
$this->formatCommentBudgetSecondsPair(microtime(true) - $commentPhaseStart, $commentBudgetSeconds),
));
return Command::SUCCESS; return Command::SUCCESS;
} }
/**
* Absolute used/budget wall seconds for the comment phase, e.g. "127.4/600 s" (not a percentage).
*/
private function formatCommentBudgetSecondsPair(float $usedSeconds, int $budgetSeconds): string
{
$r = round($usedSeconds, 1);
$uStr = abs($r - (float) (int) $r) < 0.01 ? (string) (int) $r : sprintf('%.1f', $r);
return sprintf('%s/%d s', $uStr, $budgetSeconds);
}
private function createPrewarmProgressBar(SymfonyStyle $io, int $max, string $message = ''): ProgressBar private function createPrewarmProgressBar(SymfonyStyle $io, int $max, string $message = ''): ProgressBar
{ {
$bar = $io->createProgressBar($max); $bar = $io->createProgressBar($max);
@ -325,6 +345,27 @@ final class PrewarmCommand extends Command
return $bar; return $bar;
} }
/**
* ProgressBar::finish() sets progress to max; when the comment phase stops on budget, we only
* completed part of the steps, so cap max to the current step first (or clear if nothing ran).
*/
private function finishPrewarmProgressBarWithoutFillingToMax(ProgressBar $bar, SymfonyStyle $io): void
{
$max = (int) $bar->getMaxSteps();
$done = (int) $bar->getProgress();
if ($max > 0 && $done < $max && $done === 0) {
if (method_exists($bar, 'clear')) {
$bar->clear();
}
} else {
if ($max > 0 && $done < $max && $done > 0) {
$bar->setMaxSteps($done);
}
$bar->finish();
}
$io->newLine(2);
}
/** /**
* @param object{silent?: bool} $controller * @param object{silent?: bool} $controller
*/ */

Loading…
Cancel
Save