From 6b3f81805d3b5774f67dfcf2e48af78aa77871c9 Mon Sep 17 00:00:00 2001 From: "Corey N. Runkel" Date: Thu, 26 Mar 2026 13:21:23 -0400 Subject: [PATCH 1/5] Add stop event child to S3Mediator --- apps/state_mediator/lib/state_mediator.ex | 29 ++++++++++++++++++- .../lib/state_mediator/s3_mediator.ex | 2 +- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/apps/state_mediator/lib/state_mediator.ex b/apps/state_mediator/lib/state_mediator.ex index 64bff4a5..89a61492 100644 --- a/apps/state_mediator/lib/state_mediator.ex +++ b/apps/state_mediator/lib/state_mediator.ex @@ -14,7 +14,8 @@ defmodule StateMediator do crowding_children( app_value(:commuter_rail_crowding, :enabled) == "true", crowding_source - ) + ) ++ + stop_event_children(app_value(:stop_events, :enabled) == "true") # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html # for other strategies and supported options @@ -155,6 +156,32 @@ defmodule StateMediator do [] end + @spec stop_event_children(boolean()) :: [ + :supervisor.child_spec() | {module(), term()} | module() + ] + defp stop_event_children(true) do + Logger.info("#{__MODULE__} STOP_EVENTS_ENABLED=true") + + [ + { + StateMediator.S3Mediator, + [ + spec_id: :stop_event_mediator, + bucket_arn: app_value(:stop_events, :s3_bucket), + object: app_value(:stop_events, :s3_object), + interval: 3 * 1_000, + sync_timeout: 30_000, + state: State.StopEvent + ] + } + ] + end + + defp stop_event_children(false) do + Logger.info("#{__MODULE__} STOP_EVENTS_ENABLED=false") + [] + end + @doc false def source_url(mod) do case Application.get_env(:state_mediator, mod)[:source] do diff --git a/apps/state_mediator/lib/state_mediator/s3_mediator.ex b/apps/state_mediator/lib/state_mediator/s3_mediator.ex index 8ff19cf5..1b072cce 100644 --- a/apps/state_mediator/lib/state_mediator/s3_mediator.ex +++ b/apps/state_mediator/lib/state_mediator/s3_mediator.ex @@ -96,7 +96,7 @@ defmodule StateMediator.S3Mediator do state ) do Logger.warning( - "Received unknown response when getting commuter rail occupancies from S3: #{inspect(response)}" + "Received unknown response when fetching data via S3Mediator: #{inspect(response)}" ) schedule_update(state) From b1a995f08085610d07d472fc9608c681bfd41a57 Mon Sep 17 00:00:00 2001 From: "Corey N. Runkel" Date: Thu, 26 Mar 2026 13:21:54 -0400 Subject: [PATCH 2/5] Update config to look for stop events env vars --- apps/state_mediator/config/config.exs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/state_mediator/config/config.exs b/apps/state_mediator/config/config.exs index 56731792..21791154 100644 --- a/apps/state_mediator/config/config.exs +++ b/apps/state_mediator/config/config.exs @@ -15,6 +15,11 @@ config :state_mediator, :commuter_rail_crowding, s3_object: {:system, "CR_CROWDING_S3_OBJECT"}, source: {:system, "CR_CROWING_SOURCE", "s3"} +config :state_mediator, :stop_events, + enabled: {:system, "STOP_EVENTS_ENABLED", "false"}, + s3_bucket: {:system, "STOP_EVENTS_S3_BUCKET"}, + s3_object: {:system, "STOP_EVENTS_S3_OBJECT"} + config :state_mediator, Realtime, gtfs_url: {:system, "MBTA_GTFS_URL", "https://cdn.mbta.com/MBTA_GTFS.zip"}, alert_url: {:system, "ALERT_URL", "https://cdn.mbta.com/realtime/Alerts_enhanced.json"} From 90003806152b384afd5600ef49bd840eee3e5e06 Mon Sep 17 00:00:00 2001 From: "Corey N. Runkel" Date: Thu, 26 Mar 2026 13:22:16 -0400 Subject: [PATCH 3/5] Update State to use Parse.StopEvents --- apps/state/lib/state/stop_event.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/state/lib/state/stop_event.ex b/apps/state/lib/state/stop_event.ex index 09be272f..c8ee688a 100644 --- a/apps/state/lib/state/stop_event.ex +++ b/apps/state/lib/state/stop_event.ex @@ -4,6 +4,7 @@ defmodule State.StopEvent do """ use State.Server, indices: [:id, :trip_id, :stop_id, :route_id, :vehicle_id], + parser: Parse.StopEvents, recordable: Model.StopEvent alias Model.Route From c52500ae8a0d71d8990026730742101ea8b4e615 Mon Sep 17 00:00:00 2001 From: "Corey N. Runkel" Date: Thu, 26 Mar 2026 13:23:46 -0400 Subject: [PATCH 4/5] Update README --- README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1a5ebf70..2e2e8561 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,22 @@ To start your Phoenix app: - Run `asdf plugin-add poetry` to add Poetry plugin 4. Run `asdf install` to install plugin versions specified in `.tool-versions` file 2. Install dependencies with `mix deps.get` - 3. Setup `apps/api_accounts` following directions in `apps/api_accounts/README.md` (on [GitHub](apps/api_accounts/README.md#setting-up-dynamodb-local) or [ExDoc](api_accounts-readme.html#setting-up-dynamodb-local)) - 4. Start Phoenix endpoint with `mix phx.server` + 3. Install development dependencies with `mix deps.get --only dev` + 4. Setup `apps/api_accounts` following directions in `apps/api_accounts/README.md` (on [GitHub](apps/api_accounts/README.md#setting-up-dynamodb-local) or [ExDoc](api_accounts-readme.html#setting-up-dynamodb-local)) + 5. Start Phoenix endpoint with `mix phx.server` Now you can visit [`localhost:4000`](http://localhost:4000) from your browser. +> [!WARNING] +> Your app will fail when calling `mix phx.server` if `STOP_EVENTS_ENALBED` or `CR_CROWDING_ENABLED` are `true` unless: +> +> 1. `ExAws` can find AWS credentials (such as `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`) +> 2. S3 bucket and object environment variables retrieved by `config/config.exs` are available +> 3. Your credentials have permissions on those objects +> +> To circumvent these issues, set `STOP_EVENTS_ENALBED` and `CR_CROWDING_ENABLED` to `false`. + + ## Tests To run the tests, first install and setup Colima, Docker, and docker-compose: From 52b8ffeee6e7f68a71f93c25b56a8c51c6e8dfab Mon Sep 17 00:00:00 2001 From: "Corey N. Runkel" Date: Thu, 26 Mar 2026 15:04:06 -0400 Subject: [PATCH 5/5] Correct README --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2e2e8561..a4cc109f 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,8 @@ To start your Phoenix app: - Run `asdf plugin-add poetry` to add Poetry plugin 4. Run `asdf install` to install plugin versions specified in `.tool-versions` file 2. Install dependencies with `mix deps.get` - 3. Install development dependencies with `mix deps.get --only dev` - 4. Setup `apps/api_accounts` following directions in `apps/api_accounts/README.md` (on [GitHub](apps/api_accounts/README.md#setting-up-dynamodb-local) or [ExDoc](api_accounts-readme.html#setting-up-dynamodb-local)) - 5. Start Phoenix endpoint with `mix phx.server` + 3. Setup `apps/api_accounts` following directions in `apps/api_accounts/README.md` (on [GitHub](apps/api_accounts/README.md#setting-up-dynamodb-local) or [ExDoc](api_accounts-readme.html#setting-up-dynamodb-local)) + 4. Start Phoenix endpoint with `mix phx.server` Now you can visit [`localhost:4000`](http://localhost:4000) from your browser.