prop/config/config.exs
Graham McIntire cc3dc41a6b
Fix all medium findings and split contact_live_test.exs
- Fix N+1 queries in radio.ex (preload :user)
- Add encryption_salt to session options
- Consolidate token deletion to single query
- Wrap gunzip in try/rescue for corrupt files
- Add Cache.match_delete/1 to encapsulate ETS access
- Precompute sec_i_factor_ref as module attribute
- Guard EXLA.Backend config to dev/test only
- Split 3505-line contact_live_test.exs into 4 files
- Replace Process.sleep with :sys.get_state synchronization
- Replace Process.alive? with DOM output assertions
- Clarify router.ex comment for non-live_session routes
- Update findings.md to reflect fixes
2026-05-29 15:53:04 -05:00

184 lines
6.9 KiB
Elixir
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# This file is responsible for configuring your application
# and its dependencies with the aid of the Config module.
#
# This configuration file is loaded before any dependency and
# is restricted to this project.
# General application configuration
import Config
alias Microwaveprop.Workers.CanadianSoundingFetchWorker
# Configure esbuild (the version is required)
config :esbuild,
version: "0.27.4",
microwaveprop: [
args:
~w(js/app.ts --bundle --target=es2022 --format=esm --splitting --outdir=../priv/static/assets/js --external:/fonts/* --external:/images/* --alias:@=.),
cd: Path.expand("../assets", __DIR__),
env: %{"NODE_PATH" => [Path.expand("../deps", __DIR__), Mix.Project.build_path()]}
]
config :live_table,
app: :microwaveprop,
repo: Microwaveprop.Repo,
pubsub: Microwaveprop.PubSub,
defaults: %{
custom_footer: {MicrowavepropWeb.LiveTableFooter, :render}
}
# Configure Elixir's Logger
config :logger, :default_formatter,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id, :remote_ip, :method, :request_path]
# Configure the mailer
#
# By default it uses the "Local" adapter which stores the emails
# locally. You can see the emails in your browser, at "/dev/mailbox".
#
# For production it's recommended to configure a different adapter
# at the `config/runtime.exs`.
config :microwaveprop, Microwaveprop.Mailer, adapter: Swoosh.Adapters.Local
# PromEx metrics exporter. We surface the `/metrics` Prometheus scrape
# endpoint via MicrowavepropWeb.Router rather than PromEx's own HTTP
# server, so the router (and optional bearer-token auth in
# MicrowavepropWeb.MetricsPlug) stay the single ingress path. Grafana
# auto-provisioning is off — dashboards live in the dedicated Grafana
# instance and are managed separately.
config :microwaveprop, Microwaveprop.PromEx,
disabled: false,
manual_metrics_start_delay: :no_delay,
drop_metrics_groups: [],
grafana: :disabled,
metrics_server: :disabled
# Configure the endpoint
config :microwaveprop, MicrowavepropWeb.Endpoint,
url: [host: "localhost"],
adapter: Bandit.PhoenixAdapter,
render_errors: [
formats: [html: MicrowavepropWeb.ErrorHTML, json: MicrowavepropWeb.ErrorJSON],
layout: false
],
pubsub_server: Microwaveprop.PubSub,
live_view: [signing_salt: "Gdq36xze"]
config :microwaveprop, Oban,
engine: Oban.Pro.Engines.Smart,
repo: Microwaveprop.Repo,
queues: [
solar: 1,
weather: 20,
enqueue: 1,
gefs: 2,
terrain: 4,
# DO NOT raise above 1 without measuring per-pod RSS first.
# RoverPathProfileWorker runs the full PathCompute pipeline
# (terrain sample analysis + 9 HRRR profile fetches/decodes +
# sounding readout + ionosphere readout + per-band scoring +
# loss + power + 18 h forecast). Per-job heap is roughly the
# same shape as the :propagation grid chain — ~500 MiB peak.
# With the deployment.yaml memory limit at 6 GiB and steady-state
# hot pods sitting at 3-5 GiB (ScoreCache + GridCache + LiveView
# state), even 2 concurrent path-computes can push a hot pod past
# the limit and trigger OOMKill. Verified on 2026-05-03: a
# backfill flood ran 3 slots/pod × 4 hot pods on the :terrain
# queue and OOMKilled two pods in a CrashLoopBackOff cycle.
# If you need more throughput, prefer adding hot replicas (HPA
# max is 4 in k8s/hpa.yaml) over raising this slot count, OR
# offload the HRRR profile fetch to hrrr-point-rs first.
rover_path: 1,
commercial: 2,
iemre: 10,
# 2 slots so PropagationPruneWorker can run alongside the
# forecast-hour chain job.
propagation: 2,
admin: 1,
nexrad: 2,
radar: 2,
ionosphere: 1,
space_weather: 1,
mechanism: 4,
contact_import: 4,
# HRDPS Canadian propagation chain seeder. Single slot — the worker
# only inserts grid_tasks rows, so concurrent execution buys nothing
# and uniqueness is enforced by the (run_time, kind, source) index.
# Dormant until the Rust prop-grid-rs HRDPS branch ships and the
# cron entry in runtime.exs is uncommented.
hrdps: 1
],
plugins: [
{Oban.Plugins.Pruner, max_age: 3600 * 24},
# See runtime.exs — producer-record-based orphan rescue, not
# timer-based. Fast recovery from rolling deploys.
{Oban.Pro.Plugins.DynamicLifeline, rescue_interval: to_timeout(second: 30)},
{Oban.Plugins.Cron,
crontab: [
{"0 8 * * *", Microwaveprop.Workers.SolarIndexWorker},
{"*/5 * * * *", Microwaveprop.Commercial.PollWorker},
{"5 * * * *", Microwaveprop.Workers.PropagationGridWorker},
{"*/15 * * * *", Microwaveprop.Workers.PropagationPruneWorker},
{"15 * * * *", Microwaveprop.Workers.GridCachePruneWorker},
# Heals rover-planning missions whose paths are stuck in :pending
# or :failed (transient elevation-API errors, interrupted enqueues).
{"30 * * * *", Microwaveprop.Workers.RoverMissionBackfillWorker},
# UWYO publishes the 00Z/12Z Canadian radiosondes ~90 minutes after launch
{"30 1 * * *", CanadianSoundingFetchWorker},
{"30 13 * * *", CanadianSoundingFetchWorker},
# GIRO ionosonde stations publish at ~7.5 min cadence; poll every
# 10 min to pick up fresh foF2/foEs/hmF2 within one cycle.
{"*/10 * * * *", Microwaveprop.Workers.IonosphereFetchWorker},
# NOAA SWPC publishes Kp and GOES X-ray at 1-min cadence and F10.7
# hourly; poll every 5 min for reasonable freshness vs request volume.
{"*/5 * * * *", Microwaveprop.Workers.SpaceWeatherFetchWorker}
]}
]
# Per-band scoring weights file produced by `scripts/recalibrate.py`.
# Read once at app start by `Microwaveprop.Propagation.BandWeights` and
# cached in `:persistent_term`. Set to `false` to ignore the file and
# fall back to in-source `:weights` overrides + `@weights` defaults.
config :microwaveprop, :band_weights_json, "priv/algo/band_weights.json"
config :microwaveprop, :scopes,
user: [
default: true,
module: Microwaveprop.Accounts.Scope,
assign_key: :current_scope,
access_path: [:user, :id],
schema_key: :user_id,
schema_type: :binary_id,
schema_table: :users,
test_data_fixture: Microwaveprop.AccountsFixtures,
test_setup_helper: :register_and_log_in_user
]
config :microwaveprop,
ecto_repos: [Microwaveprop.Repo],
generators: [timestamp_type: :utc_datetime, binary_id: true]
# Use EXLA as default Nx backend for accelerated tensor operations
if Mix.env() in [:dev, :test] do
config :nx, :default_backend, EXLA.Backend
end
# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason
# Configure tailwind (the version is required)
config :tailwind,
version: "4.2.2",
microwaveprop: [
args: ~w(
--input=assets/css/app.css
--output=priv/static/assets/css/app.css
),
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
cd: Path.expand("..", __DIR__)
]
import_config "#{config_env()}.exs"