4
0
mirror of https://github.com/AzuraCast/AzuraCast.git synced 2024-06-14 21:26:37 +00:00
AzuraCast/src/Sync/Runner.php
2021-02-21 22:19:02 -06:00

207 lines
6.0 KiB
PHP

<?php
namespace App\Sync;
use App\Entity\Repository\SettingsRepository;
use App\Environment;
use App\Event\GetSyncTasks;
use App\EventDispatcher;
use App\LockFactory;
use App\Message;
use Monolog\Handler\StreamHandler;
use Monolog\Logger;
use Psr\Log\LogLevel;
/**
* The runner of scheduled synchronization tasks.
*/
class Runner
{
protected Logger $logger;
protected Environment $environment;
protected SettingsRepository $settingsRepo;
protected LockFactory $lockFactory;
protected EventDispatcher $eventDispatcher;
public function __construct(
SettingsRepository $settingsRepo,
Environment $environment,
Logger $logger,
LockFactory $lockFactory,
EventDispatcher $eventDispatcher
) {
$this->settingsRepo = $settingsRepo;
$this->environment = $environment;
$this->logger = $logger;
$this->lockFactory = $lockFactory;
$this->eventDispatcher = $eventDispatcher;
}
public function __invoke(Message\AbstractMessage $message): void
{
if ($message instanceof Message\RunSyncTaskMessage) {
$outputPath = $message->outputPath;
if (null !== $outputPath) {
$logHandler = new StreamHandler($outputPath, LogLevel::DEBUG, true);
$this->logger->pushHandler($logHandler);
}
$this->runSyncTask($message->type, true);
if (null !== $outputPath) {
$this->logger->popHandler();
}
}
}
public function runSyncTask(string $type, bool $force = false): void
{
// Immediately halt if setup is not complete.
$settings = $this->settingsRepo->readSettings();
if (!$settings->isSetupComplete()) {
$this->logger->notice(
sprintf('Skipping sync task %s; setup not complete.', $type)
);
return;
}
$allSyncInfo = $this->getSyncTimes();
if (!isset($allSyncInfo[$type])) {
throw new \InvalidArgumentException(sprintf('Invalid sync task: %s', $type));
}
$syncInfo = $allSyncInfo[$type];
set_time_limit($syncInfo['timeout']);
$this->logger->notice(
sprintf('Running sync task: %s', $syncInfo['name']),
[
'force' => $force,
]
);
$lock = $this->lockFactory->createLock('sync_' . $type, $syncInfo['timeout']);
if ($force) {
$this->lockFactory->clearQueue('sync_' . $type);
try {
$lock->acquire($force);
} catch (\Exception $e) {
// Noop
}
} elseif (!$lock->acquire()) {
return;
}
try {
$event = new GetSyncTasks($type);
$this->eventDispatcher->dispatch($event);
$tasks = $event->getTasks();
foreach ($tasks as $taskClass => $task) {
if (!$force && !$lock->isAcquired()) {
$this->logger->error(
sprintf('Lock timed out before task %s can run.', $taskClass)
);
return;
}
$this->logger->debug(sprintf(
'Starting sub-task: %s',
$taskClass
));
$start_time = microtime(true);
$task->run($force);
$end_time = microtime(true);
$time_diff = $end_time - $start_time;
$this->logger->debug(
sprintf(
'Timer "%s" completed in %01.3f second(s).',
$taskClass,
round($time_diff, 3)
)
);
}
$settings = $this->settingsRepo->readSettings(true);
$settings->updateSyncLastRunTime($type);
$this->settingsRepo->writeSettings($settings);
} finally {
$lock->release();
}
$this->logger->debug(
sprintf('Sync task "%s" completed successfully.', $syncInfo['name']),
);
}
/**
* @return mixed[]
*/
public function getSyncTimes(): array
{
$shortTaskTimeout = $this->environment->getSyncShortExecutionTime();
$longTaskTimeout = $this->environment->getSyncLongExecutionTime();
$settings = $this->settingsRepo->readSettings();
$syncs = [
GetSyncTasks::SYNC_NOWPLAYING => [
'name' => __('Now Playing Data'),
'contents' => [
__('Now Playing Data'),
],
'timeout' => $shortTaskTimeout,
'latest' => $settings->getSyncNowplayingLastRun(),
'interval' => 15,
],
GetSyncTasks::SYNC_SHORT => [
'name' => __('1-Minute Sync'),
'contents' => [
__('Song Requests Queue'),
],
'timeout' => $shortTaskTimeout,
'latest' => $settings->getSyncShortLastRun(),
'interval' => 60,
],
GetSyncTasks::SYNC_MEDIUM => [
'name' => __('5-Minute Sync'),
'contents' => [
__('Check Media Folders'),
],
'timeout' => $shortTaskTimeout,
'latest' => $settings->getSyncMediumLastRun(),
'interval' => 300,
],
GetSyncTasks::SYNC_LONG => [
'name' => __('1-Hour Sync'),
'contents' => [
__('Analytics/Statistics'),
__('Cleanup'),
],
'timeout' => $longTaskTimeout,
'latest' => $settings->getSyncLongLastRun(),
'interval' => 3600,
],
];
foreach ($syncs as &$sync_info) {
$sync_info['diff'] = time() - $sync_info['latest'];
}
return $syncs;
}
}