Add database and Redis port configuration support, connection health checks, and refactor worker status endpoint.

This commit is contained in:
Jeppe Bundgaard
2026-03-20 13:01:21 +01:00
parent 219f739b54
commit de89c4d635
7 changed files with 138 additions and 21 deletions
+27 -5
View File
@@ -4,6 +4,7 @@ $CONFIG_DB = [
'user' => '', // Username of the database server e.g. root
'password' => '', // Password of the database server e.g. password123
'database' => '', // Name of the database e.g. my_database
'port' => 3306, // Port of the database server e.g. 3306
'ssl_mode' => 'DISABLED' // SSL mode for mysqldump: DISABLED, PREFERRED, REQUIRED, VERIFY_CA, VERIFY_IDENTITY
];
$DEBUG = true; // Set to true to enable debugging (Error messages will be shown, and this should never be used in production)
@@ -33,8 +34,10 @@ $MINIO = [
$SLACK_DEFAULT_WEBHOOK = ''; // Default Slack webhook URL e.g. https://hooks.slack.com/services/XXXXXXXXX/XXXXXXXXX/XXXXXXXXXXXXXXXXXXXXXXXX
$REDIS_CONFIG = [
'host' => '', // Redis host (IP address)
'user' => '', // Redis user
'database' => 0, // Redis database number (0-15)
'password' => '' // Redis password
'password' => '', // Redis password
'port' => 6379 // Redis port
];
// Set the timezone
@@ -50,6 +53,7 @@ if (isset($_ENV['USE_ENV']) && $_ENV['USE_ENV'] === 'true') {
'CONFIG_DB_USER' => 'user',
'CONFIG_DB_PASSWORD' => 'password',
'CONFIG_DB_DATABASE' => 'database',
'CONFIG_DB_PORT' => 'port',
'CONFIG_DB_SSL_MODE' => 'ssl_mode',
'DEBUG' => 'DEBUG',
'ENCRYPTION_KEY' => 'ENCRYPTION_KEY',
@@ -66,7 +70,9 @@ if (isset($_ENV['USE_ENV']) && $_ENV['USE_ENV'] === 'true') {
'SLACK_DEFAULT_WEBHOOK' => 'SLACK_DEFAULT_WEBHOOK',
'REDIS_CONFIG_HOST' => 'host',
'REDIS_CONFIG_DATABASE' => 'database',
'REDIS_CONFIG_PASSWORD' => 'password'
'REDIS_CONFIG_PASSWORD' => 'password',
'REDIS_CONFIG_PORT' => 'port',
'REDIS_CONFIG_USER' => 'user'
];
$dbTarget = strtolower(trim((string)($_ENV['CONFIG_DB_TARGET'] ?? 'live')));
if ($dbTarget !== 'live' && $dbTarget !== 'debug') {
@@ -94,6 +100,7 @@ if (isset($_ENV['USE_ENV']) && $_ENV['USE_ENV'] === 'true') {
'user' => $resolveDbValue('USER'),
'password' => $resolveDbValue('PASSWORD'),
'database' => $resolveDbValue('DATABASE'),
'port' => (int)($resolveDbValue('PORT') ?: 3306),
'ssl_mode' => $resolveDbValue('SSL_MODE') !== '' ? $resolveDbValue('SSL_MODE') : 'DISABLED'
];
/**
@@ -140,13 +147,28 @@ if (isset($_ENV['USE_ENV']) && $_ENV['USE_ENV'] === 'true') {
* Set the Slack default webhook
*/
$SLACK_DEFAULT_WEBHOOK = $_ENV['SLACK_DEFAULT_WEBHOOK'];
$resolveRedisValue = function (string $key) use ($dbTarget): string {
$liveKey = 'REDIS_CONFIG_' . $key;
$debugKey = 'REDIS_CONFIG_DEBUG_' . $key;
$liveValue = (string)($_ENV[$liveKey] ?? '');
$debugValue = (string)($_ENV[$debugKey] ?? '');
if ($dbTarget === 'debug' && $debugValue !== '') {
return $debugValue;
}
return $liveValue;
};
/**
* Set the Redis configuration
*/
$REDIS_CONFIG = [
'host' => $_ENV['REDIS_CONFIG_HOST'],
'database' => $_ENV['REDIS_CONFIG_DATABASE'],
'password' => $_ENV['REDIS_CONFIG_PASSWORD']
'host' => $resolveRedisValue('HOST'),
'user' => $resolveRedisValue('USER'),
'database' => $resolveRedisValue('DATABASE'),
'password' => $resolveRedisValue('PASSWORD'),
'port' => (int)($resolveRedisValue('PORT') ?: 6379)
];
// Set the timezone
+35 -6
View File
@@ -13,6 +13,7 @@ class db
private string $user;
private string $password;
private string $database;
private int $port = 3306;
private string $ssl_mode = 'DISABLED'; // mysqldump SSL mode (e.g., DISABLED, PREFERRED, REQUIRED, VERIFY_CA, VERIFY_IDENTITY)
public function __construct(array $config)
@@ -21,6 +22,9 @@ class db
$this->user = $config['user'];
$this->password = $config['password'];
$this->database = $config['database'];
if (isset($config['port']) && is_numeric($config['port'])) {
$this->port = (int)$config['port'];
}
if (isset($config['ssl_mode']) && is_string($config['ssl_mode']) && $config['ssl_mode'] !== '') {
$this->ssl_mode = $config['ssl_mode'];
}
@@ -28,22 +32,46 @@ class db
public static function getPDO(): \PDO
{
global $config;
$dsn = "mysql:host={$config['db']['host']};dbname={$config['db']['database']};charset=utf8mb4";
return new \PDO($dsn, $config['db']['user'], $config['db']['password'], [
global $CONFIG_DB;
$port = $CONFIG_DB['port'] ?? 3306;
$dsn = "mysql:host={$CONFIG_DB['host']};port={$port};dbname={$CONFIG_DB['database']};charset=utf8mb4";
return new \PDO($dsn, $CONFIG_DB['user'], $CONFIG_DB['password'], [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => false,
]);
}
public function testConnection(): bool
{
try {
$conn = new mysqli($this->host, $this->user, $this->password, $this->database, $this->port);
if ($conn->connect_error) {
return false;
}
$this->conn = $conn;
return true;
} catch (Exception) {
return false;
}
}
public function connect(): void
{
global $response;
try {
$this->conn = new mysqli($this->host, $this->user, $this->password, $this->database);
// Enable error reporting for mysqli to catch connection issues via exceptions
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$this->conn = new mysqli($this->host, $this->user, $this->password, $this->database, $this->port);
if ($this->conn->connect_error) {
throw new Exception($this->conn->connect_error);
}
} catch (Exception $e) {
$response->internal_server_error($e->getMessage());
if ($response) {
$response->internal_server_error("Database connection failed: " . $e->getMessage());
} else {
throw $e;
}
}
}
@@ -170,9 +198,10 @@ class db
$user = escapeshellarg($this->user);
$pass = escapeshellarg($this->password);
$db = escapeshellarg($this->database);
$port = (int)$this->port;
$outfile = escapeshellarg($path);
$sslPart = $sslFlag !== '' ? ($sslFlag . ' ') : '';
$command = "mysqldump {$sslPart}-h $host -u $user --password=$pass $db > $outfile 2>&1";
$command = "mysqldump {$sslPart}-h $host -P $port -u $user --password=$pass $db > $outfile 2>&1";
exec($command, $output, $return);
// Check if the command was successful
return $return === 0;
+18
View File
@@ -17,8 +17,12 @@ class redis implements redis_i
}
// Apply the Redis configuration
$this->redis_host = $REDIS_CONFIG['host'];
$this->redis_user = $REDIS_CONFIG['user'] ?? '';
$this->redis_database = $REDIS_CONFIG['database'];
$this->redis_password = $REDIS_CONFIG['password'];
if (isset($REDIS_CONFIG['port']) && is_numeric($REDIS_CONFIG['port'])) {
$this->redis_port = (int)$REDIS_CONFIG['port'];
}
}
@@ -500,4 +504,18 @@ class redis implements redis_i
$this->delete('perm:' . $cache_key);
return $this;
}
/**
* @throws \Exception
*/
public function ping(): bool
{
if (!self::is_connected()) {
self::connect();
}
if (!self::is_connected()) {
return false;
}
return true;
}
}
+27 -6
View File
@@ -10,6 +10,7 @@ if (isset($_ENV['USE_ENV']) && $_ENV['USE_ENV'] === 'true') {
'CONFIG_DB_USER' => 'user',
'CONFIG_DB_PASSWORD' => 'password',
'CONFIG_DB_DATABASE' => 'database',
'CONFIG_DB_PORT' => 'port',
'DEBUG' => 'DEBUG',
'ENCRYPTION_KEY' => 'ENCRYPTION_KEY',
'CORS' => 'CORS',
@@ -25,7 +26,9 @@ if (isset($_ENV['USE_ENV']) && $_ENV['USE_ENV'] === 'true') {
'SLACK_DEFAULT_WEBHOOK' => 'SLACK_DEFAULT_WEBHOOK',
'REDIS_CONFIG_HOST' => 'host',
'REDIS_CONFIG_DATABASE' => 'database',
'REDIS_CONFIG_PASSWORD' => 'password'
'REDIS_CONFIG_PASSWORD' => 'password',
'REDIS_CONFIG_PORT' => 'port',
'REDIS_CONFIG_USER' => 'user'
];
$dbTarget = strtolower(trim((string)($_ENV['CONFIG_DB_TARGET'] ?? 'live')));
if ($dbTarget !== 'live' && $dbTarget !== 'debug') {
@@ -52,7 +55,9 @@ if (isset($_ENV['USE_ENV']) && $_ENV['USE_ENV'] === 'true') {
'host' => $resolveDbValue('HOST'),
'user' => $resolveDbValue('USER'),
'password' => $resolveDbValue('PASSWORD'),
'database' => $resolveDbValue('DATABASE')
'database' => $resolveDbValue('DATABASE'),
'port' => (int)($resolveDbValue('PORT') ?: 3306),
'ssl_mode' => $resolveDbValue('SSL_MODE') ?: 'DISABLED'
];
/**
* Set the debug configuration
@@ -98,17 +103,33 @@ if (isset($_ENV['USE_ENV']) && $_ENV['USE_ENV'] === 'true') {
* Set the Slack default webhook
*/
$SLACK_DEFAULT_WEBHOOK = $_ENV['SLACK_DEFAULT_WEBHOOK'];
$resolveRedisValue = function (string $key) use ($dbTarget): string {
$liveKey = 'REDIS_CONFIG_' . $key;
$debugKey = 'REDIS_CONFIG_DEBUG_' . $key;
$liveValue = (string)($_ENV[$liveKey] ?? '');
$debugValue = (string)($_ENV[$debugKey] ?? '');
if ($dbTarget === 'debug' && $debugValue !== '') {
return $debugValue;
}
return $liveValue;
};
/**
* Set the Redis configuration
*/
$REDIS_CONFIG = [
'host' => $_ENV['REDIS_CONFIG_HOST'],
'database' => $_ENV['REDIS_CONFIG_DATABASE'],
'password' => $_ENV['REDIS_CONFIG_PASSWORD']
'host' => $resolveRedisValue('HOST'),
'user' => $resolveRedisValue('USER'),
'database' => $resolveRedisValue('DATABASE'),
'password' => $resolveRedisValue('PASSWORD'),
'port' => (int)($resolveRedisValue('PORT') ?: 6379)
];
// Set the timezone
date_default_timezone_set($_ENV['CONFIG_TIMEZONE']) ?? 'Europe/Copenhagen';
$timezone = $_ENV['CONFIG_TIMEZONE'] ?? 'Europe/Copenhagen';
date_default_timezone_set($timezone);
// Set the all config
$ALL_CONFIG = $_ENV; // This is used by the backup job.
+18 -2
View File
@@ -2,6 +2,7 @@
namespace routes;
use classes\db;
use classes\economic;
use classes\router;
use classes\shelly;
@@ -124,7 +125,7 @@ class workerRoute
});
$this->get('/worker/status', function () {
global /** @var router $router */
$response, $router;
$response, $router, $db;
$response->success([
'message' => 'Worker is running',
'status' => 'OK',
@@ -132,7 +133,22 @@ class workerRoute
'timezone' => date_default_timezone_get(),
'host' => gethostname(),
'version' => '1.0.1',
'routes' => $router->countRoutes()
'routes' => $router->countRoutes(),
'redis' => [
'host' => $_ENV['REDIS_CONFIG_HOST'],
'user' => $_ENV['REDIS_CONFIG_USER'],
'database' => $_ENV['REDIS_CONFIG_DATABASE'],
//'password' => $_ENV['REDIS_CONFIG_PASSWORD'],
'port' => $_ENV['REDIS_CONFIG_PORT'],
'status' => redis->ping() ? 'OK' : 'ERROR',
],
'database' => [
'host' => $_ENV['CONFIG_DB_HOST'],
'database' => $_ENV['CONFIG_DB_DATABASE'],
'user' => $_ENV['CONFIG_DB_USER'],
'status' => $db->testConnection() ? 'OK' : 'ERROR',
],
]);
});
$this->get('/worker/debug', function () {
@@ -11,6 +11,7 @@ it('can connect to a configured MySQL instance in integration mode', function ()
$user = getenv('CONFIG_DB_USER') ?: null;
$password = getenv('CONFIG_DB_PASSWORD') ?: '';
$database = getenv('CONFIG_DB_DATABASE') ?: null;
$port = getenv('CONFIG_DB_PORT') ?: 3306;
if (!$host || !$user || !$database) {
test()->markTestSkipped('Missing DB env vars: CONFIG_DB_HOST/CONFIG_DB_USER/CONFIG_DB_DATABASE.');
@@ -30,6 +31,7 @@ it('can connect to a configured MySQL instance in integration mode', function ()
'user' => $user,
'password' => $password,
'database' => $database,
'port' => $port,
]);
$db->connect();
+11 -2
View File
@@ -18,6 +18,11 @@ trait redis_t
* @var string
*/
protected string $redis_host = '';
/**
* The Redis user
* @var string
*/
protected string $redis_user = '';
/**
* The Redis port
* @var int
@@ -88,13 +93,17 @@ trait redis_t
public function connect(): self
{
$this->redis = new PredisClient([
$params = [
'scheme' => $this->redis_scheme,
'host' => $this->redis_host,
'port' => $this->redis_port,
'password' => $this->redis_password,
'database' => $this->redis_database
]);
];
if ($this->redis_user !== '' && $this->redis_user !== 'default') {
$params['username'] = $this->redis_user;
}
$this->redis = new PredisClient($params);
// Check if the connection was successful
if (!self::is_connected()) {