Skip to content

feat(SystemStatus.SubwayCache): save status#3342

Closed
thecristen wants to merge 1 commit into
mainfrom
cbj/subway-cache-insert
Closed

feat(SystemStatus.SubwayCache): save status#3342
thecristen wants to merge 1 commit into
mainfrom
cbj/subway-cache-insert

Conversation

@thecristen

Copy link
Copy Markdown
Collaborator

Just noticed this while I was inspecting memory usage on the homepage. The homepage can call subway_status() and trigger a new computation of Subway Status. This PR enhances that by not only sending the newly-fetched status to the homepage, but also saving it into the ETS table for later retrieval!

@thecristen
thecristen requested a review from a team as a code owner July 17, 2026 20:25
@thecristen
thecristen requested a review from joshlarson July 17, 2026 20:25

@joshlarson joshlarson left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this will do anything. The ETS table is defined as protected, which means that processes other than the SubwayCache GenServer won't be able to write to it. When I tested this out by having init/1 not write to the :subway_status table, I just got an error message:

2026-07-20 11:01:50.937 [error] mbta_id=43634282 request_id=GMQHmiH5yG7feH0AAAZi state=set duration=14.232 status=500 params={} path=/ method=GET headers={}
2026-07-20 11:01:50.941 [error] mbta_id=43634282 request_id=GMQHmiH5yG7feH0AAAZi ** (ArgumentError) errors were found at the given arguments:

  * 1st argument: the table identifier refers to an ETS table with insufficient access rights

    (stdlib 7.3) :ets.insert(:subway_status, {"status", %{"Blue" => [%{branch_ids: [], status_entries: [%{status: :normal, time: :current, alerts: [], multiple: false}]}], "Green" => [%{branch_ids: [], status_entries: [%{status: :delay, time: :current, alerts: [%Alerts.Alert{id: "1023051", active_period: [{#DateTime<2026-07-20 10:40:00-04:00 EDT America/New_York>, #DateTime<2026-07-20 13:01:31-04:00 EDT America/New_Yor
k>}], banner: nil, cause: :unknown_cause, created_at: #DateTime<2026-07-20 10:40:54-04:00 EDT America/New_York>, description: nil, effect: :delay, header: "Green Line: Delays of about 15 minutes due to an earlier disabled train at Park Street. Service is proceeding.", image: nil, image_alternative_text: nil, informed_entity: %Alerts.InformedEntitySet{activities: MapSet.new([:exit, :ride, :board]), direction_id: MapSet.
new([nil]), entities: [%Alerts.InformedEntity{activities: MapSet.new([:exit, :ride, :board]), direction_id: nil, facility: nil, route: "Green-E", route_type: 0, stop: nil, trip: nil}, %Alerts.InformedEntity{activities: MapSet.new([:exit, :ride, :board]), direction_id: nil, facility: nil, route: "Green", route_type: 0, stop: nil, trip: nil}, %Alerts.InformedEntity{activities: MapSet.new([:exit, :ride, :board]), directio
n_id: nil, facility: nil, route: "Green-B", route_type: 0, stop: nil, trip: nil}, %Alerts.InformedEntity{activities: MapSet.new([:exit, :ride, :board]), direction_id: nil, facility: nil, route: "Green-C", route_type: 0, stop: nil, trip: nil}, %Alerts.InformedEntity{activities: MapSet.new([:exit, :ride, :board]), direction_id: nil, facility: nil, route: "Green-D", route_type: 0, stop: nil, trip: nil}], facility: MapSet.
new([nil]), route: MapSet.new(["Green", ...]), ...}, ...}], ...}]}, ...], ...}})
    (dotcom 0.0.1) lib/dotcom/system_status/subway_cache.ex:31: Dotcom.SystemStatus.SubwayCache.subway_status/0
    (dotcom 0.0.1) lib/dotcom_web/controllers/page_controller.ex:142: DotcomWeb.PageController.subway_status/2
    (dotcom 0.0.1) lib/dotcom_web/controllers/page_controller.ex:1: DotcomWeb.PageController.phoenix_controller_pipeline/2
    (phoenix 1.8.6) lib/phoenix/router.ex:416: Phoenix.Router.__call__/5
    (dotcom 0.0.1) deps/plug/lib/plug/error_handler.ex:80: DotcomWeb.Router.call/2
    (dotcom 0.0.1) lib/dotcom_web/endpoint.ex:1: DotcomWeb.Endpoint.plug_builder_call/2
    (dotcom 0.0.1) deps/plug/lib/plug/debugger.ex:155: DotcomWeb.Endpoint."call (overridable 3)"/2
    (dotcom 0.0.1) lib/dotcom_web/endpoint.ex:1: DotcomWeb.Endpoint."call (overridable 4)"/2
    (dotcom 0.0.1) lib/dotcom_web/endpoint.ex:1: DotcomWeb.Endpoint.call/2
    (phoenix 1.8.6) lib/phoenix/endpoint/sync_code_reload_plug.ex:22: Phoenix.Endpoint.SyncCodeReloadPlug.do_call/4
    (bandit 1.10.4) lib/bandit/pipeline.ex:131: Bandit.Pipeline.call_plug!/2
    (bandit 1.10.4) lib/bandit/pipeline.ex:42: Bandit.Pipeline.run/5
    (bandit 1.10.4) lib/bandit/http1/handler.ex:13: Bandit.HTTP1.Handler.handle_data/3
    (bandit 1.10.4) lib/bandit/delegating_handler.ex:18: Bandit.DelegatingHandler.handle_data/3
    (bandit 1.10.4) lib/bandit/delegating_handler.ex:8: Bandit.DelegatingHandler.handle_info/2
    (stdlib 7.3) gen_server.erl:2434: :gen_server.try_handle_info/3
    (stdlib 7.3) gen_server.erl:2420: :gen_server.handle_msg/3
    (stdlib 7.3) proc_lib.erl:333: :proc_lib.init_p_do_apply/3

That said... this use case is exceedingly rare - the :subway_status ETS table is only empty for the 1 second or so on app startup, and I'm not entirely sure that the DotcomWeb process will even start serving traffic before SubwayCache.init/1 has returned anyway, which means that this might be infinitely rare!

@thecristen

Copy link
Copy Markdown
Collaborator Author

Thanks for the sanity check!

@thecristen thecristen closed this Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants