diff --git a/Dockerfile b/Dockerfile index f9bf36c72..ebcfe8967 100644 --- a/Dockerfile +++ b/Dockerfile @@ -51,6 +51,10 @@ COPY ./util/docker/mariadb /bd_build/mariadb/ RUN bash /bd_build/mariadb/setup.sh \ && rm -rf /bd_build/mariadb +COPY ./util/docker/redis /bd_build/redis/ +RUN bash /bd_build/redis/setup.sh \ + && rm -rf /bd_build/redis + # # START Operations as `azuracast` user # diff --git a/bin/uptime_wait b/bin/uptime_wait index d65a11320..45fd9e56c 100644 --- a/bin/uptime_wait +++ b/bin/uptime_wait @@ -74,7 +74,7 @@ class UptimeWait $elapsed = 0; while ($elapsed <= $this->timeout) { - if ($this->checkDatabase()) { + if ($this->checkRedis() && $this->checkDatabase()) { $this->println('Services started up and ready!'); die(0); } @@ -119,6 +119,54 @@ class UptimeWait } } + protected function checkRedis(): bool + { + $enableRedis = $this->envToBool($_ENV['ENABLE_REDIS'] ?? true); + $redisHost = $_ENV['REDIS_HOST'] ?? 'localhost'; + $redisPort = (int)($_ENV['REDIS_PORT'] ?? 6379); + $redisDb = (int)($_ENV['REDIS_DB'] ?? 1); + + $redisSocket = ('localhost' === $redisHost) + ? '/run/redis/redis.sock' + : null; + + if (!$enableRedis) { + $this->println('Redis disabled; skipping Redis check...'); + return true; + } + + try { + $redis = new Redis(); + if (null !== $redisSocket) { + $redis->connect($redisSocket); + } else { + $redis->connect($redisHost, $redisPort, 15); + } + $redis->select($redisDb); + + $redis->ping(); + + return true; + } catch (Throwable $e) { + if ($this->debugMode) { + $this->println($e->getMessage()); + } + + return false; + } + } + + protected function envToBool(string|bool $value): bool + { + if (is_bool($value)) { + return $value; + } + + return str_starts_with(strtolower($value), 'y') + || 'true' === strtolower($value) + || '1' === $value; + } + protected function println(string $line): void { echo $line . "\n"; diff --git a/config/services.php b/config/services.php index d8e9fafe5..5bb7c99aa 100644 --- a/config/services.php +++ b/config/services.php @@ -145,19 +145,41 @@ return [ App\Doctrine\ReloadableEntityManagerInterface::class => DI\Get(App\Doctrine\DecoratedEntityManager::class), Doctrine\ORM\EntityManagerInterface::class => DI\Get(App\Doctrine\DecoratedEntityManager::class), + // Redis cache + Redis::class => static function (Environment $environment) { + if (!$environment->enableRedis()) { + throw new App\Exception\BootstrapException('Redis is disabled on this installation.'); + } + + $settings = $environment->getRedisSettings(); + + $redis = new Redis(); + if (isset($settings['socket'])) { + $redis->connect($settings['socket']); + } else { + $redis->connect($settings['host'], $settings['port'], 15); + } + $redis->select($settings['db']); + + return $redis; + }, + Symfony\Contracts\Cache\CacheInterface::class => static function ( Environment $environment, - Psr\Log\LoggerInterface $logger + Psr\Log\LoggerInterface $logger, + ContainerInterface $di ) { if ($environment->isTesting()) { $cacheInterface = new Symfony\Component\Cache\Adapter\ArrayAdapter(); - } else { + } elseif (!$environment->enableRedis()) { $tempDir = $environment->getTempDirectory() . DIRECTORY_SEPARATOR . 'cache'; $cacheInterface = new Symfony\Component\Cache\Adapter\FilesystemAdapter( '', 0, $tempDir ); + } else { + $cacheInterface = new Symfony\Component\Cache\Adapter\RedisAdapter($di->get(Redis::class)); } $cacheInterface->setLogger($logger); @@ -170,14 +192,24 @@ return [ Psr\Cache\CacheItemPoolInterface::class => DI\get( Symfony\Contracts\Cache\CacheInterface::class ), - Psr\SimpleCache\CacheInterface::class => static fn( - Psr\Cache\CacheItemPoolInterface $cache - ) => new Symfony\Component\Cache\Psr16Cache($cache), + Psr\SimpleCache\CacheInterface::class => static function (Psr\Cache\CacheItemPoolInterface $cache) { + return new Symfony\Component\Cache\Psr16Cache($cache); + }, // Symfony Lock adapter - Symfony\Component\Lock\PersistingStoreInterface::class => static fn( + Symfony\Component\Lock\PersistingStoreInterface::class => static function ( + ContainerInterface $di, Environment $environment - ) => new Symfony\Component\Lock\Store\FlockStore($environment->getTempDirectory()), + ) { + if ($environment->enableRedis()) { + $redis = $di->get(Redis::class); + $store = new Symfony\Component\Lock\Store\RedisStore($redis); + } else { + $store = new Symfony\Component\Lock\Store\FlockStore($environment->getTempDirectory()); + } + + return $store; + }, // Console App\Console\Application::class => static function ( @@ -313,7 +345,7 @@ return [ Symfony\Component\Messenger\MessageBus::class => static function ( App\MessageQueue\QueueManager $queueManager, - App\LockFactory $lockFactory, + App\Lock\LockFactory $lockFactory, Monolog\Logger $logger, ContainerInterface $di, App\Plugins $plugins, diff --git a/src/Console/Command/Sync/AbstractSyncCommand.php b/src/Console/Command/Sync/AbstractSyncCommand.php index 526554b32..f8f679206 100644 --- a/src/Console/Command/Sync/AbstractSyncCommand.php +++ b/src/Console/Command/Sync/AbstractSyncCommand.php @@ -6,7 +6,7 @@ namespace App\Console\Command\Sync; use App\Console\Command\CommandAbstract; use App\Environment; -use App\LockFactory; +use App\Lock\LockFactory; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Lock\Lock; diff --git a/src/Console/Command/Sync/NowPlayingCommand.php b/src/Console/Command/Sync/NowPlayingCommand.php index 4fc7d65a6..56b4b267d 100644 --- a/src/Console/Command/Sync/NowPlayingCommand.php +++ b/src/Console/Command/Sync/NowPlayingCommand.php @@ -6,7 +6,7 @@ namespace App\Console\Command\Sync; use App\Entity\Repository\SettingsRepository; use App\Environment; -use App\LockFactory; +use App\Lock\LockFactory; use Doctrine\ORM\EntityManagerInterface; use Psr\Log\LoggerInterface; use Symfony\Component\Console\Attribute\AsCommand; diff --git a/src/Console/Command/Sync/RunnerCommand.php b/src/Console/Command/Sync/RunnerCommand.php index 95ab563b7..d1b5519f8 100644 --- a/src/Console/Command/Sync/RunnerCommand.php +++ b/src/Console/Command/Sync/RunnerCommand.php @@ -7,7 +7,7 @@ namespace App\Console\Command\Sync; use App\Entity\Repository\SettingsRepository; use App\Environment; use App\Event\GetSyncTasks; -use App\LockFactory; +use App\Lock\LockFactory; use App\Sync\Task\AbstractTask; use Carbon\CarbonImmutable; use Cron\CronExpression; diff --git a/src/Entity/Settings.php b/src/Entity/Settings.php index 2ce74f71c..737e1cdb5 100644 --- a/src/Entity/Settings.php +++ b/src/Entity/Settings.php @@ -201,10 +201,7 @@ class Settings implements Stringable } #[ - OA\Property( - description: "Whether to use high-performance static JSON for Now Playing data updates.", - example: "false" - ), + OA\Property(description: "Whether to use high-performance static JSON for Now Playing data updates.", example: "false"), ORM\Column, Groups(self::GROUP_GENERAL) ] diff --git a/src/Environment.php b/src/Environment.php index 7252bf36b..e35e43439 100644 --- a/src/Environment.php +++ b/src/Environment.php @@ -58,6 +58,11 @@ final class Environment public const DB_USER = 'MYSQL_USER'; public const DB_PASSWORD = 'MYSQL_PASSWORD'; + public const ENABLE_REDIS = 'ENABLE_REDIS'; + public const REDIS_HOST = 'REDIS_HOST'; + public const REDIS_PORT = 'REDIS_PORT'; + public const REDIS_DB = 'REDIS_DB'; + // Default settings private array $defaults = [ self::APP_NAME => 'AzuraCast', @@ -71,6 +76,8 @@ final class Environment self::AUTO_ASSIGN_PORT_MIN => 8000, self::AUTO_ASSIGN_PORT_MAX => 8499, + self::ENABLE_REDIS => true, + self::SYNC_SHORT_EXECUTION_TIME => 600, self::SYNC_LONG_EXECUTION_TIME => 1800, @@ -293,9 +300,27 @@ final class Environment return $dbSettings; } - public function useLocalDatabase(): bool + public function enableRedis(): bool { - return 'localhost' === ($this->data[self::DB_HOST] ?? 'localhost'); + return self::envToBool($this->data[self::ENABLE_REDIS] ?? true); + } + + /** + * @return mixed[] + */ + public function getRedisSettings(): array + { + $redisSettings = [ + 'host' => $this->data[self::REDIS_HOST] ?? 'localhost', + 'port' => (int)($this->data[self::REDIS_PORT] ?? 6379), + 'db' => (int)($this->data[self::REDIS_DB] ?? 1), + ]; + + if ('localhost' === $redisSettings['host'] && $this->isDocker()) { + $redisSettings['socket'] = '/run/redis/redis.sock'; + } + + return $redisSettings; } public function isProfilingExtensionEnabled(): bool diff --git a/src/Installer/EnvFiles/AzuraCastEnvFile.php b/src/Installer/EnvFiles/AzuraCastEnvFile.php index 968c8128e..d9a3fade9 100644 --- a/src/Installer/EnvFiles/AzuraCastEnvFile.php +++ b/src/Installer/EnvFiles/AzuraCastEnvFile.php @@ -28,6 +28,7 @@ final class AzuraCastEnvFile extends AbstractEnvFile } $dbSettings = $emptyEnv->getDatabaseSettings(); + $redisSettings = $emptyEnv->getRedisSettings(); $config = [ Environment::LANG => [ @@ -151,6 +152,28 @@ final class AzuraCastEnvFile extends AbstractEnvFile ), 'default' => 100, ], + Environment::ENABLE_REDIS => [ + 'name' => __('Enable Redis'), + 'description' => __( + 'Disable to use a flatfile cache instead of Redis.', + ), + ], + Environment::REDIS_HOST => [ + 'name' => __('Redis Host'), + 'default' => $redisSettings['host'], + 'required' => true, + ], + Environment::REDIS_PORT => [ + 'name' => __('Redis Port'), + 'default' => $redisSettings['port'], + 'required' => true, + ], + Environment::REDIS_DB => [ + 'name' => __('Redis Database Index'), + 'options' => range(0, 15), + 'default' => $redisSettings['db'], + 'required' => true, + ], 'PHP_MAX_FILE_SIZE' => [ 'name' => __('PHP Maximum POST File Size'), 'default' => '25M', diff --git a/src/LockFactory.php b/src/Lock/LockFactory.php similarity index 84% rename from src/LockFactory.php rename to src/Lock/LockFactory.php index 807d3e841..e2685e2b9 100644 --- a/src/LockFactory.php +++ b/src/Lock/LockFactory.php @@ -2,10 +2,11 @@ declare(strict_types=1); -namespace App; +namespace App\Lock; use Exception; use Psr\Log\LoggerInterface; +use Symfony\Component\Lock\BlockingStoreInterface; use Symfony\Component\Lock\LockFactory as SymfonyLockFactory; use Symfony\Component\Lock\LockInterface; use Symfony\Component\Lock\PersistingStoreInterface; @@ -16,6 +17,11 @@ final class LockFactory extends SymfonyLockFactory PersistingStoreInterface $lockStore, LoggerInterface $logger ) { + if (!$lockStore instanceof BlockingStoreInterface) { + $lockStore = new RetryTillSaveStore($lockStore, 30, 1000); + $lockStore->setLogger($logger); + } + parent::__construct($lockStore); $this->setLogger($logger); } diff --git a/src/Lock/RetryTillSaveStore.php b/src/Lock/RetryTillSaveStore.php new file mode 100644 index 000000000..cc93c2b87 --- /dev/null +++ b/src/Lock/RetryTillSaveStore.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Lock; + +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Psr\Log\NullLogger; +use Symfony\Component\Lock\BlockingStoreInterface; +use Symfony\Component\Lock\Exception\LockConflictedException; +use Symfony\Component\Lock\Key; +use Symfony\Component\Lock\PersistingStoreInterface; + +use const PHP_INT_MAX; + +/** + * Copied from Symfony 5.x as it was deprecated in 6.x with no suitable replacement. + * + * RetryTillSaveStore is a PersistingStoreInterface implementation which decorate a non blocking + * PersistingStoreInterface to provide a blocking storage. + * + * @author Jérémy Derussé + */ +final class RetryTillSaveStore implements BlockingStoreInterface, LoggerAwareInterface +{ + use LoggerAwareTrait; + + /** + * @param int $retrySleep Duration in ms between 2 retry + * @param int $retryCount Maximum amount of retry + */ + public function __construct( + private readonly PersistingStoreInterface $decorated, + private readonly int $retrySleep = 100, + private readonly int $retryCount = PHP_INT_MAX + ) { + $this->logger = new NullLogger(); + } + + /** + * {@inheritdoc} + */ + public function save(Key $key): void + { + $this->decorated->save($key); + } + + /** + * {@inheritdoc} + */ + public function waitAndSave(Key $key): void + { + $retry = 0; + $sleepRandomness = (int)($this->retrySleep / 10); + do { + try { + $this->decorated->save($key); + + return; + } catch (LockConflictedException) { + usleep(($this->retrySleep + random_int(-$sleepRandomness, $sleepRandomness)) * 1000); + } + } while (++$retry < $this->retryCount); + + $this->logger?->warning( + 'Failed to store the "{resource}" lock. Abort after {retry} retry.', + ['resource' => $key, 'retry' => $retry] + ); + + throw new LockConflictedException(); + } + + /** + * {@inheritdoc} + */ + public function putOffExpiration(Key $key, float $ttl): void + { + $this->decorated->putOffExpiration($key, $ttl); + } + + /** + * {@inheritdoc} + */ + public function delete(Key $key): void + { + $this->decorated->delete($key); + } + + /** + * {@inheritdoc} + */ + public function exists(Key $key): bool + { + return $this->decorated->exists($key); + } +} diff --git a/src/MessageQueue/HandleUniqueMiddleware.php b/src/MessageQueue/HandleUniqueMiddleware.php index 9d0d980b1..db97c49e9 100644 --- a/src/MessageQueue/HandleUniqueMiddleware.php +++ b/src/MessageQueue/HandleUniqueMiddleware.php @@ -4,7 +4,7 @@ declare(strict_types=1); namespace App\MessageQueue; -use App\LockFactory; +use App\Lock\LockFactory; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; use Symfony\Component\Messenger\Middleware\MiddlewareInterface; @@ -14,7 +14,7 @@ use Symfony\Component\Messenger\Stamp\ConsumedByWorkerStamp; final class HandleUniqueMiddleware implements MiddlewareInterface { public function __construct( - private readonly LockFactory $lockFactory + protected LockFactory $lockFactory ) { } diff --git a/src/RateLimit.php b/src/RateLimit.php index b3ca57039..5d6ea628d 100644 --- a/src/RateLimit.php +++ b/src/RateLimit.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace App; use App\Http\ServerRequest; +use App\Lock\LockFactory; use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\Cache\Adapter\ProxyAdapter; use Symfony\Component\RateLimiter\RateLimiterFactory; diff --git a/src/Service/LastFm.php b/src/Service/LastFm.php index 99d8b2397..561545ded 100644 --- a/src/Service/LastFm.php +++ b/src/Service/LastFm.php @@ -6,7 +6,7 @@ namespace App\Service; use App\Entity; use App\Exception\RateLimitExceededException; -use App\LockFactory; +use App\Lock\LockFactory; use App\Version; use GuzzleHttp\Client; use GuzzleHttp\RequestOptions; diff --git a/src/Service/MusicBrainz.php b/src/Service/MusicBrainz.php index b2094f719..b2300dc34 100644 --- a/src/Service/MusicBrainz.php +++ b/src/Service/MusicBrainz.php @@ -6,7 +6,7 @@ namespace App\Service; use App\Entity; use App\Exception\RateLimitExceededException; -use App\LockFactory; +use App\Lock\LockFactory; use App\Version; use GuzzleHttp\Client; use GuzzleHttp\Psr7\UriResolver; diff --git a/src/Service/ServiceControl.php b/src/Service/ServiceControl.php index cd8b6d9b0..844ab2591 100644 --- a/src/Service/ServiceControl.php +++ b/src/Service/ServiceControl.php @@ -4,7 +4,6 @@ declare(strict_types=1); namespace App\Service; -use App\Environment; use App\Exception\SupervisorException; use App\Service\ServiceControl\ServiceData; use Supervisor\Exception\Fault\BadNameException; @@ -27,7 +26,7 @@ final class ServiceControl { $services = []; - foreach ($this->getServiceNames() as $name => $description) { + foreach (self::getServiceNames() as $name => $description) { try { $isRunning = in_array( $this->supervisor->getProcess($name)->getState(), @@ -53,7 +52,7 @@ final class ServiceControl public function restart(string $service): void { - $serviceNames = $this->getServiceNames(); + $serviceNames = self::getServiceNames(); if (!isset($serviceNames[$service])) { throw new \InvalidArgumentException( sprintf('Service "%s" is not managed by AzuraCast.', $service) @@ -72,9 +71,9 @@ final class ServiceControl } } - public function getServiceNames(): array + public static function getServiceNames(): array { - $services = [ + return [ 'beanstalkd' => __('Message queue delivery service'), 'cron' => __('Runs routine synchronized tasks'), 'mariadb' => __('Database'), @@ -82,6 +81,7 @@ final class ServiceControl 'php-fpm' => __('PHP FastCGI Process Manager'), 'php-nowplaying' => __('Now Playing manager service'), 'php-worker' => __('PHP queue processing worker'), + 'redis' => __('Cache'), 'sftpgo' => __('SFTP service'), 'centrifugo' => __('Live Now Playing updates'), ]; diff --git a/util/ansible/deploy.yml b/util/ansible/deploy.yml index 429d1041c..f03c8929c 100644 --- a/util/ansible/deploy.yml +++ b/util/ansible/deploy.yml @@ -23,6 +23,7 @@ - supervisord - nginx - php + - redis - beanstalkd - sftpgo - mariadb diff --git a/util/ansible/roles/influxdb/tasks/main.yml b/util/ansible/roles/influxdb/tasks/main.yml new file mode 100644 index 000000000..9dad7f4bf --- /dev/null +++ b/util/ansible/roles/influxdb/tasks/main.yml @@ -0,0 +1,13 @@ +--- +- name: Shut Down InfluxDB + service: + name: "influxdb" + state: stopped + ignore_errors: true + +- name: Remove InfluxDB if Present + apt: + name: "influxdb" + state: absent + force: true + purge: true diff --git a/util/ansible/roles/redis/tasks/main.yml b/util/ansible/roles/redis/tasks/main.yml new file mode 100644 index 000000000..a0bb9730b --- /dev/null +++ b/util/ansible/roles/redis/tasks/main.yml @@ -0,0 +1,35 @@ +--- +- name: Add Redis PPA repository (Focal) + apt_repository: + repo: "ppa:chris-lea/redis-server" + update_cache: true + when: ansible_distribution_release == 'focal' + +- name: Install Redis + apt: + name: redis-server + +- name: Install Redis Conf + template: + src: redis.conf.j2 + dest: /etc/redis/redis.conf + force: true + owner: "redis" + mode: 0644 + +- name: Install Redis Supervisord conf + template: + src: supervisor.conf.j2 + dest: /etc/supervisor/conf.d/redis.conf + force: true + mode: 0644 + +- name: Disable Redis services + service: + name: "{{ item }}" + enabled: false + state: stopped + ignore_errors: true + with_items: + - "redis-server" + - "redis" diff --git a/util/ansible/roles/redis/templates/redis.conf.j2 b/util/ansible/roles/redis/templates/redis.conf.j2 new file mode 100644 index 000000000..bdd93ed57 --- /dev/null +++ b/util/ansible/roles/redis/templates/redis.conf.j2 @@ -0,0 +1,14 @@ +bind 127.0.0.1 +protected-mode yes +port 6379 + +save "" + +appendonly no + +maxmemory 128mb +maxmemory-policy volatile-lfu + +always-show-logo no + +protected-mode no diff --git a/util/ansible/roles/redis/templates/supervisor.conf.j2 b/util/ansible/roles/redis/templates/supervisor.conf.j2 new file mode 100644 index 000000000..28e754564 --- /dev/null +++ b/util/ansible/roles/redis/templates/supervisor.conf.j2 @@ -0,0 +1,6 @@ +[program:redis] +command=/usr/bin/redis-server /etc/redis/redis.conf +user=redis +numprocs=1 +autostart=true +autorestart=unexpected diff --git a/util/ansible/update.yml b/util/ansible/update.yml index c9711b17f..e05a5f9b1 100644 --- a/util/ansible/update.yml +++ b/util/ansible/update.yml @@ -30,6 +30,9 @@ - role: "nginx" when: update_revision|int < 90 + - role: "redis" + when: update_revision|int < 93 + - role: "beanstalkd" when: update_revision|int < 87 @@ -41,6 +44,9 @@ - role: "composer" + - role: "influxdb" + when: update_revision|int < 58 + - role: "ufw" when: update_revision|int < 86 diff --git a/util/docker/redis/redis/redis.conf b/util/docker/redis/redis/redis.conf new file mode 100644 index 000000000..2c6405111 --- /dev/null +++ b/util/docker/redis/redis/redis.conf @@ -0,0 +1,14 @@ +unixsocket /run/redis/redis.sock +unixsocketperm 666 + +bind 127.0.0.1 +port 6379 + +save "" + +appendonly no + +maxmemory 128mb +maxmemory-policy volatile-lfu + +always-show-logo no diff --git a/util/docker/redis/service.minimal/redis.conf b/util/docker/redis/service.minimal/redis.conf new file mode 100644 index 000000000..d472c26bb --- /dev/null +++ b/util/docker/redis/service.minimal/redis.conf @@ -0,0 +1,15 @@ +[program:redis] +command=redis-server /etc/redis/redis.conf +user=redis +priority=100 +numprocs=1 +autostart=true +autorestart=true + +stdout_logfile=/var/azuracast/www_tmp/service_redis.log +stdout_logfile_maxbytes=5MB +stdout_logfile_backups=5 +redirect_stderr=true + +stdout_events_enabled = true +stderr_events_enabled = true diff --git a/util/docker/redis/setup.sh b/util/docker/redis/setup.sh new file mode 100644 index 000000000..f41ea111c --- /dev/null +++ b/util/docker/redis/setup.sh @@ -0,0 +1,28 @@ +#!/bin/bash +set -e +set -x + +apt-get update + +# Install common scripts +# cp -rT /bd_build/redis/scripts/ /usr/local/bin + +cp -rT /bd_build/redis/startup_scripts/. /etc/my_init.d/ + +cp -rT /bd_build/redis/service.minimal/. /etc/supervisor/minimal.conf.d/ + +# cp -rT /bd_build/redis/service.full/. /etc/supervisor/full.conf.d/ + +# Run service setup for all setup scripts +for f in /bd_build/redis/setup/*.sh; do + bash "$f" -H +done + +# Cleanup +apt-get -y autoremove +apt-get clean +rm -rf /var/lib/apt/lists/* +rm -rf /tmp/tmp* + +chmod -R a+x /usr/local/bin +chmod -R +x /etc/my_init.d diff --git a/util/docker/redis/setup/redis.sh b/util/docker/redis/setup/redis.sh new file mode 100644 index 000000000..c332e5da5 --- /dev/null +++ b/util/docker/redis/setup/redis.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e +set -x + +apt-get install -y --no-install-recommends redis-server + +cp /bd_build/redis/redis/redis.conf /etc/redis/redis.conf +chown redis:redis /etc/redis/redis.conf diff --git a/util/docker/redis/startup_scripts/00_disable_redis.sh b/util/docker/redis/startup_scripts/00_disable_redis.sh new file mode 100644 index 000000000..9824f1598 --- /dev/null +++ b/util/docker/redis/startup_scripts/00_disable_redis.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +bool() { + case "$1" in + Y* | y* | true | TRUE | 1) return 0 ;; + esac + return 1 +} + +# If Redis is expressly disabled or the host is anything but localhost, disable Redis on this container. +ENABLE_REDIS=${ENABLE_REDIS:-true} + +if [ "$REDIS_HOST" != "localhost" ] || ! bool "$ENABLE_REDIS"; then + echo "Redis is disabled or host is not localhost; disabling Redis..." + rm -rf /etc/supervisor/minimal.conf.d/redis.conf +fi