From 4a448e551787d2f0fe1ddf5ab564008798c6e92a Mon Sep 17 00:00:00 2001 From: Jamil Date: Mon, 28 Jul 2025 11:13:52 -0400 Subject: [PATCH] fix(portal): separate dev and runtime Oban configs (#10027) Oban includes its own configuration validation, which seems to prevent `runtime.exs` from overriding any compile-time options. This prevents us from using ENV vars to configure it, such as restricting job execution to `domain` nodes by setting `queues: []`. To fix that, we make sure to set Oban configuration in env-specific files `config/dev.exs` and `config/test.exs`, and at runtime for prod with `config/runtime.exs`. Fixes #10016 --- elixir/config/config.exs | 22 ---------------------- elixir/config/dev.exs | 24 ++++++++++++++++++++++++ elixir/config/runtime.exs | 29 +++++++++++++++++++++++------ elixir/config/test.exs | 25 +++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 28 deletions(-) diff --git a/elixir/config/config.exs b/elixir/config/config.exs index 1d03052b2..90123143d 100644 --- a/elixir/config/config.exs +++ b/elixir/config/config.exs @@ -202,28 +202,6 @@ config :domain, outbound_email_adapter_configured?: false config :domain, web_external_url: "http://localhost:13000" -config :domain, Oban, - plugins: [ - # Keep the last 90 days of completed, cancelled, and discarded jobs - {Oban.Plugins.Pruner, max_age: 60 * 60 * 24 * 90}, - - # Rescue jobs that may have failed due to transient errors like deploys - # or network issues. It's not guaranteed that the job won't be executed - # twice, so for now we disable it since all of our Oban jobs can be retried - # without loss. - # {Oban.Plugins.Lifeline, rescue_after: :timer.minutes(30)} - - # Periodic jobs - {Oban.Plugins.Cron, - crontab: [ - # Delete expired flows every minute - {"* * * * *", Domain.Flows.Jobs.DeleteExpiredFlows} - ]} - ], - queues: [default: 10], - engine: Oban.Engines.Basic, - repo: Domain.Repo - ############################### ##### Web ##################### ############################### diff --git a/elixir/config/dev.exs b/elixir/config/dev.exs index 2639f6dc5..f2e4f4d31 100644 --- a/elixir/config/dev.exs +++ b/elixir/config/dev.exs @@ -20,6 +20,30 @@ config :domain, Domain.Billing, secret_key: System.get_env("STRIPE_SECRET_KEY", "sk_dev_1111"), webhook_signing_secret: System.get_env("STRIPE_WEBHOOK_SIGNING_SECRET", "whsec_dev_1111") +# Oban has its own config validation that prevents overriding config in runtime.exs, +# so we explicitly set the config in dev.exs, test.exs, and runtime.exs (for prod) only. +config :domain, Oban, + plugins: [ + # Keep the last 90 days of completed, cancelled, and discarded jobs + {Oban.Plugins.Pruner, max_age: 60 * 60 * 24 * 90}, + + # Rescue jobs that may have failed due to transient errors like deploys + # or network issues. It's not guaranteed that the job won't be executed + # twice, so for now we disable it since all of our Oban jobs can be retried + # without loss. + # {Oban.Plugins.Lifeline, rescue_after: :timer.minutes(30)} + + # Periodic jobs + {Oban.Plugins.Cron, + crontab: [ + # Delete expired flows every minute + {"* * * * *", Domain.Flows.Jobs.DeleteExpiredFlows} + ]} + ], + queues: [default: 10], + engine: Oban.Engines.Basic, + repo: Domain.Repo + ############################### ##### Web ##################### ############################### diff --git a/elixir/config/runtime.exs b/elixir/config/runtime.exs index 7a0489f8f..15d174d32 100644 --- a/elixir/config/runtime.exs +++ b/elixir/config/runtime.exs @@ -148,13 +148,30 @@ if config_env() == :prod do env_var_to_config!(:background_jobs_enabled) and Enum.member?(env_var_to_config!(:auth_provider_adapters), :mock) + # Oban has its own config validation that prevents overriding config in runtime.exs, + # so we explicitly set the config in dev.exs, test.exs, and runtime.exs (for prod) only. config :domain, Oban, - queues: - if(env_var_to_config!(:background_jobs_enabled), - do: [default: 10], - # Using an empty queue prevents jobs from running on other nodes - else: [] - ) + # Periodic jobs don't make sense in tests + plugins: [ + # Keep the last 90 days of completed, cancelled, and discarded jobs + {Oban.Plugins.Pruner, max_age: 60 * 60 * 24 * 90}, + + # Rescue jobs that may have failed due to transient errors like deploys + # or network issues. It's not guaranteed that the job won't be executed + # twice, so for now we disable it since all of our Oban jobs can be retried + # without loss. + # {Oban.Plugins.Lifeline, rescue_after: :timer.minutes(30)} + + # Periodic jobs + {Oban.Plugins.Cron, + crontab: [ + # Delete expired flows every minute + {"* * * * *", Domain.Flows.Jobs.DeleteExpiredFlows} + ]} + ], + queues: if(env_var_to_config!(:background_jobs_enabled), do: [default: 10], else: []), + engine: Oban.Engines.Basic, + repo: Domain.Repo if web_external_url = env_var_to_config!(:web_external_url) do %{ diff --git a/elixir/config/test.exs b/elixir/config/test.exs index 7603f00bb..093a41de9 100644 --- a/elixir/config/test.exs +++ b/elixir/config/test.exs @@ -20,6 +20,31 @@ config :domain, Domain.Repo, pool: Ecto.Adapters.SQL.Sandbox, queue_target: 1000 +# Oban has its own config validation that prevents overriding config in runtime.exs, +# so we explicitly set the config in dev.exs, test.exs, and runtime.exs (for prod) only. +config :domain, Oban, + # Periodic jobs don't make sense in tests + plugins: [ + # Keep the last 90 days of completed, cancelled, and discarded jobs + # {Oban.Plugins.Pruner, max_age: 60 * 60 * 24 * 90}, + + # Rescue jobs that may have failed due to transient errors like deploys + # or network issues. It's not guaranteed that the job won't be executed + # twice, so for now we disable it since all of our Oban jobs can be retried + # without loss. + # {Oban.Plugins.Lifeline, rescue_after: :timer.minutes(30)} + + # Periodic jobs + # {Oban.Plugins.Cron, + # crontab: [ + # # Delete expired flows every minute + # {"* * * * *", Domain.Flows.Jobs.DeleteExpiredFlows} + # ]} + ], + queues: [default: 10], + engine: Oban.Engines.Basic, + repo: Domain.Repo + config :domain, Domain.ChangeLogs.ReplicationConnection, replication_slot_name: "test_change_logs_slot", publication_name: "test_change_logs_publication",