addOption( 'timeout', 't', InputOption::VALUE_OPTIONAL, 'Amount of time (in seconds) to run the worker process.', 600 ); } protected function execute(InputInterface $input, OutputInterface $output): int { $io = new SymfonyStyle($input, $output); $settings = $this->settingsRepo->readSettings(); if ($settings->getSyncDisabled()) { $this->logger->error('Automated synchronization is temporarily disabled.'); return 1; } $timeout = (int)$input->getOption('timeout'); $this->loop($io, $timeout); return 0; } protected function loop(SymfonyStyle $io, int $timeout): void { $threshold = time() + $timeout; while (time() < $threshold || !empty($this->processes)) { // Check existing processes. $this->checkRunningProcesses(); // Ensure a process is running for every active station. if (time() < $threshold - 5) { $activeStations = $this->em->createQuery( <<<'DQL' SELECT s.id, s.short_name, s.nowplaying_timestamp FROM App\Entity\Station s WHERE s.is_enabled = 1 DQL )->getArrayResult(); foreach ($activeStations as $activeStation) { $shortName = $activeStation['short_name']; if (!isset($this->processes[$shortName])) { $npTimestamp = (int)$activeStation['nowplaying_timestamp']; if (time() > $npTimestamp + random_int(5, 15)) { $this->start($io, $shortName); usleep(250000); } } } } $this->em->clear(); gc_collect_cycles(); usleep(1000000); } } protected function start( SymfonyStyle $io, string $shortName ): void { $this->lockAndRunConsoleCommand( $io, $shortName, 'nowplaying', [ 'azuracast:sync:nowplaying:station', $shortName, ] ); } }