Add live-reload support for Icecast frontends.

This commit is contained in:
Buster "Silver Eagle" Neece 2021-11-16 07:13:43 -06:00
parent 4bb6b72152
commit cdc3495e6d
No known key found for this signature in database
GPG Key ID: 6D9E12FF03411F4E
5 changed files with 99 additions and 35 deletions

8
composer.lock generated
View File

@ -6524,12 +6524,12 @@
"source": {
"type": "git",
"url": "https://github.com/supervisorphp/supervisor.git",
"reference": "535bd4c854a52c692d391e5f2460ae3e327e480d"
"reference": "88b83fbcd8136f0ff28ec25bcc16a209282891dc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/supervisorphp/supervisor/zipball/535bd4c854a52c692d391e5f2460ae3e327e480d",
"reference": "535bd4c854a52c692d391e5f2460ae3e327e480d",
"url": "https://api.github.com/repos/supervisorphp/supervisor/zipball/88b83fbcd8136f0ff28ec25bcc16a209282891dc",
"reference": "88b83fbcd8136f0ff28ec25bcc16a209282891dc",
"shasum": ""
},
"require": {
@ -6586,7 +6586,7 @@
"issues": "https://github.com/supervisorphp/supervisor/issues",
"source": "https://github.com/supervisorphp/supervisor/tree/main"
},
"time": "2021-06-28T07:51:26+00:00"
"time": "2021-11-16T08:17:56+00:00"
},
{
"name": "symfony/amqp-messenger",

View File

@ -114,12 +114,18 @@ class ServicesController
case 'stop':
$frontend->stop($station);
return $response->withJson(new Entity\Api\Status(true, __('Frontend stopped.')));
return $response->withJson(new Entity\Api\Status(true, __('Service stopped.')));
case 'start':
$frontend->start($station);
return $response->withJson(new Entity\Api\Status(true, __('Frontend started.')));
return $response->withJson(new Entity\Api\Status(true, __('Service started.')));
case 'reload':
$frontend->write($station);
$frontend->reload($station);
return $response->withJson(new Entity\Api\Status(true, __('Service reloaded.')));
case 'restart':
default:
@ -131,7 +137,7 @@ class ServicesController
$frontend->write($station);
$frontend->start($station);
return $response->withJson(new Entity\Api\Status(true, __('Frontend restarted.')));
return $response->withJson(new Entity\Api\Status(true, __('Service restarted.')));
}
}
@ -187,12 +193,18 @@ class ServicesController
case 'stop':
$backend->stop($station);
return $response->withJson(new Entity\Api\Status(true, __('Backend stopped.')));
return $response->withJson(new Entity\Api\Status(true, __('Service stopped.')));
case 'start':
$backend->start($station);
return $response->withJson(new Entity\Api\Status(true, __('Backend started.')));
return $response->withJson(new Entity\Api\Status(true, __('Service started.')));
case 'reload':
$backend->write($station);
$backend->reload($station);
return $response->withJson(new Entity\Api\Status(true, __('Service reloaded.')));
case 'restart':
default:
@ -204,7 +216,7 @@ class ServicesController
$backend->write($station);
$backend->start($station);
return $response->withJson(new Entity\Api\Status(true, __('Backend restarted.')));
return $response->withJson(new Entity\Api\Status(true, __('Service restarted.')));
}
}
}

View File

@ -156,6 +156,24 @@ abstract class AbstractAdapter
$this->start($station);
}
/**
* @return bool Whether this adapter supports a non-destructive reload.
*/
public function supportsReload(): bool
{
return false;
}
/**
* Execute a non-destructive reload if the adapter supports it.
*
* @param Entity\Station $station
*/
public function reload(Entity\Station $station): void
{
$this->restart($station);
}
/**
* Stop the executable service.
*

View File

@ -88,7 +88,7 @@ class Configuration
if (!$station->getIsEnabled()) {
@unlink($supervisorConfigFile);
$this->reloadSupervisorForStation($station);
$this->stopForStation($station);
return;
}
@ -98,7 +98,7 @@ class Configuration
// If no processes need to be managed, remove any existing config.
if (!$frontend->hasCommand($station) && !$backend->hasCommand($station)) {
@unlink($supervisorConfigFile);
$this->reloadSupervisorForStation($station);
$this->stopForStation($station);
return;
}
@ -140,7 +140,28 @@ class Configuration
$frontend->write($station);
$backend->write($station);
$this->reloadSupervisorForStation($station, $forceRestart);
// Reload Supervisord and process groups
$affected_groups = $this->reloadSupervisor();
$was_restarted = in_array($backend_group, $affected_groups, true);
if (!$was_restarted && $forceRestart) {
try {
if ($backend->supportsReload() || $frontend->supportsReload()) {
$backend->reload($station);
$frontend->reload($station);
} else {
$this->supervisor->stopProcessGroup($backend_group, true);
$this->supervisor->startProcessGroup($backend_group, true);
}
} catch (SupervisorException) {
}
$was_restarted = true;
}
if ($was_restarted) {
$this->markAsStarted($station);
}
}
/**
@ -152,40 +173,30 @@ class Configuration
return $configDir . '/supervisord.conf';
}
/**
* Trigger a supervisord reload/restart for a station, optionally forcing a restart of the station's
* service group.
*
* @param Station $station
* @param bool $force_restart
*/
protected function reloadSupervisorForStation(Station $station, bool $force_restart = false): bool
protected function stopForStation(Station $station): void
{
$station_group = 'station_' . $station->getId();
$affected_groups = $this->reloadSupervisor();
$was_restarted = in_array($station_group, $affected_groups, true);
if (!$was_restarted && $force_restart) {
if (!$was_restarted) {
try {
$this->supervisor->stopProcessGroup($station_group, true);
$this->supervisor->startProcessGroup($station_group, true);
$this->supervisor->stopProcessGroup($station_group, false);
} catch (SupervisorException) {
}
$was_restarted = true;
}
if ($was_restarted) {
$station->setHasStarted(true);
$station->setNeedsRestart(false);
$station->clearCache();
$this->markAsStarted($station);
}
$this->em->persist($station);
$this->em->flush();
}
protected function markAsStarted(Station $station): void
{
$station->setHasStarted(true);
$station->setNeedsRestart(false);
$station->clearCache();
return $was_restarted;
$this->em->persist($station);
$this->em->flush();
}
/**

View File

@ -12,6 +12,7 @@ use Exception;
use GuzzleHttp\Psr7\Uri;
use NowPlaying\Result\Result;
use Psr\Http\Message\UriInterface;
use Supervisor\Exception\SupervisorException as SupervisorLibException;
class Icecast extends AbstractFrontend
{
@ -25,6 +26,28 @@ class Icecast extends AbstractFrontend
return true;
}
public function supportsReload(): bool
{
return true;
}
public function reload(Entity\Station $station): void
{
if ($this->hasCommand($station)) {
$program_name = $this->getProgramName($station);
try {
$this->supervisor->signalProcess($program_name, 'HUP');
$this->logger->info(
'Adapter "' . static::class . '" reloaded.',
['station_id' => $station->getId(), 'station_name' => $station->getName()]
);
} catch (SupervisorLibException $e) {
$this->handleSupervisorException($e, $program_name, $station);
}
}
}
public function getNowPlaying(Entity\Station $station, bool $includeClients = true): Result
{
$feConfig = $station->getFrontendConfig();