From cd69de51312c1e8db389a66c0bb36afea92b5b07 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Mon, 21 Jul 2025 13:05:23 -0500 Subject: [PATCH] Fix database creation on deployment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add create_database/0 function to handle database creation before migrations - Make DeviceCache handle missing tables gracefully on startup - Retry device loading after 5 seconds if initial load fails - Prevent deployment failures when database doesn't exist yet 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- lib/aprsme/device_cache.ex | 32 ++++++++++++++++++++++++-------- lib/aprsme/release.ex | 19 +++++++++++++++++++ 2 files changed, 43 insertions(+), 8 deletions(-) diff --git a/lib/aprsme/device_cache.ex b/lib/aprsme/device_cache.ex index 2fae6b7..862c8d4 100644 --- a/lib/aprsme/device_cache.ex +++ b/lib/aprsme/device_cache.ex @@ -53,10 +53,15 @@ defmodule Aprsme.DeviceCache do @impl true def init(_) do # Load devices on startup - load_devices_into_cache() + case load_devices_into_cache() do + :ok -> + # Schedule periodic refresh + Process.send_after(self(), :refresh_cache, @refresh_interval) - # Schedule periodic refresh - Process.send_after(self(), :refresh_cache, @refresh_interval) + :error -> + # If initial load failed, retry sooner + Process.send_after(self(), :refresh_cache, 5_000) + end {:ok, %{}} end @@ -86,12 +91,23 @@ defmodule Aprsme.DeviceCache do # Private functions defp load_devices_into_cache do - devices = Repo.all(Devices) + require Logger - # Store all devices in cache - case Cachex.put(@cache_name, :all_devices, devices) do - {:ok, true} -> :ok - error -> error + try do + devices = Repo.all(Devices) + + # Store all devices in cache + case Cachex.put(@cache_name, :all_devices, devices) do + {:ok, true} -> :ok + error -> error + end + rescue + error in [Postgrex.Error, DBConnection.ConnectionError] -> + # Handle case where database or table doesn't exist yet + Logger.warning("Failed to load devices: #{inspect(error)}. Will retry later.") + # Store empty list for now + Cachex.put(@cache_name, :all_devices, []) + :error end end diff --git a/lib/aprsme/release.ex b/lib/aprsme/release.ex index 6374a93..9aa66b0 100644 --- a/lib/aprsme/release.ex +++ b/lib/aprsme/release.ex @@ -13,10 +13,29 @@ defmodule Aprsme.Release do # Gettext translations are automatically compiled during Mix compilation + # Create database if it doesn't exist + create_database() + # Run migrations {:ok, _, _} = Ecto.Migrator.with_repo(Aprsme.Repo, &Ecto.Migrator.run(&1, :up, all: true)) end + defp create_database do + require Logger + + case Aprsme.Repo.__adapter__().storage_up(Aprsme.Repo.config()) do + :ok -> + Logger.info("Database created successfully") + + {:error, :already_up} -> + Logger.info("Database already exists") + + {:error, error} -> + Logger.error("Failed to create database: #{inspect(error)}") + raise "Database creation failed: #{inspect(error)}" + end + end + def rollback(repo, version) do load_app() {:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))