diff --git a/app/Support/Settings.php b/app/Support/Settings.php index 55ea628..76bb8a7 100644 --- a/app/Support/Settings.php +++ b/app/Support/Settings.php @@ -20,25 +20,32 @@ final class Settings public static function get(string $key, mixed $default = null): mixed { - $raw = Cache::rememberForever(self::CACHE_PREFIX.$key, function () use ($key) { + $cacheKey = self::CACHE_PREFIX.$key; + + if (Cache::has($cacheKey)) { + $raw = Cache::get($cacheKey); + } else { try { $row = DB::table('app_settings')->where('key', $key)->value('value'); } catch (QueryException $e) { // The gate reads a setting on every request, so an unreachable // or not-yet-migrated table would take the whole site down — // including during a deploy where new code runs before migrate. - // Fall back to the caller's default instead, and say so. + // Fall back to the caller's default, but do NOT cache that: + // caching a failure would keep a hidden site publicly visible + // long after the database came back. Log::warning('app_settings unavailable, using default', [ 'key' => $key, 'error' => $e->getMessage(), ]); - return '__missing__'; + return $default; } // Sentinel: distinguishes "stored null" from "never stored", so a // missing row does not get re-queried on every request. - return $row === null ? '__missing__' : $row; - }); + $raw = $row ?? '__missing__'; + Cache::forever($cacheKey, $raw); + } return $raw === '__missing__' ? $default : json_decode($raw, true); } diff --git a/deploy/install.sh b/deploy/install.sh index ac8ea47..27cda5d 100755 --- a/deploy/install.sh +++ b/deploy/install.sh @@ -133,6 +133,9 @@ else set_env APP_KEY "base64:$(rand_b64 32)" set_env DB_PASSWORD "$(rand_hex 24)" + # Otherwise every installation shares the value from .env.example, reachable + # from any container on the compose network. + set_env DB_ROOT_PASSWORD "$(rand_hex 24)" set_env VPN_CONFIG_KEY "$(rand_b64 32)" set_env REVERB_APP_ID "clupilot" diff --git a/deploy/update.sh b/deploy/update.sh index 59723a0..036272a 100755 --- a/deploy/update.sh +++ b/deploy/update.sh @@ -68,6 +68,14 @@ after="$(git rev-parse HEAD)" if ! git diff --quiet "$before" "$after" -- docker/ 2>/dev/null; then log "Rebuilding the image" docker compose build --quiet app + # Recreate now, not at the end: everything below runs INSIDE this container, + # and an update that changes the PHP runtime would otherwise install and + # migrate under the old one. + docker compose up -d --force-recreate app + for _ in $(seq 1 30); do + in_app php -v >/dev/null 2>&1 && break + sleep 2 + done fi # vendor/ and node_modules/ live in the bind mount, so they shadow whatever the