Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cm/ol crowding accuracy logging #1862

Merged
merged 12 commits into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/screens/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ defmodule Screens.Application do
# Task supervisor for ScreensByAlert self-refresh jobs
{Task.Supervisor, name: Screens.ScreensByAlert.SelfRefreshRunner.TaskSupervisor},
# ScreensByAlert self-refresh job runner
{Screens.ScreensByAlert.SelfRefreshRunner, name: Screens.ScreensByAlert.SelfRefreshRunner}
{Screens.ScreensByAlert.SelfRefreshRunner, name: Screens.ScreensByAlert.SelfRefreshRunner},
Screens.OlCrowding.DynamicSupervisor
]

# See https://hexdocs.pm/elixir/Supervisor.html
Expand Down
53 changes: 53 additions & 0 deletions lib/screens/ol_crowding/dynamic_supervisor.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
defmodule Screens.OlCrowding.DynamicSupervisor do
@moduledoc false

use DynamicSupervisor
alias Screens.OlCrowding.Logger

def start_link(init_arg) do
DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
end

@impl true
def init(_init_arg) do
DynamicSupervisor.init(strategy: :one_for_one)
end

def start_logger(
original_crowding_levels,
prediction,
%{
is_real_screen: true,
screen_id: screen_id,
triptych_pane: triptych_pane
},
train_crowding_config,
fetch_predictions_fn,
fetch_parent_stop_id_fn,
fetch_params
) do
spec = %{
id: Logger,
start:
{Logger, :start_link,
[
%{
original_crowding_levels: original_crowding_levels,
prediction: prediction,
logging_options: %{
is_real_screen: true,
screen_id: screen_id,
triptych_pane: triptych_pane
},
train_crowding_config: train_crowding_config,
fetch_predictions_fn: fetch_predictions_fn,
fetch_parent_stop_id_fn: fetch_parent_stop_id_fn,
fetch_params: fetch_params
}
]},
restart: :transient
}

DynamicSupervisor.start_child(__MODULE__, spec)
end
end
67 changes: 67 additions & 0 deletions lib/screens/ol_crowding/logger.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
defmodule Screens.OlCrowding.Logger do
@moduledoc false

require Logger
use GenServer

alias Screens.Predictions.Prediction

def start_link(opts) do
GenServer.start_link(__MODULE__, opts)
end

@impl true
def init(state) do
schedule_run()

{:ok, state}
end

@impl true
def handle_info(
:run,
%{
original_crowding_levels: original_crowding_levels,
prediction: prediction,
logging_options: %{
is_real_screen: true,
screen_id: screen_id,
triptych_pane: triptych_pane
},
train_crowding_config: train_crowding_config,
fetch_predictions_fn: fetch_predictions_fn,
fetch_parent_stop_id_fn: fetch_parent_stop_id_fn,
fetch_params: fetch_params
} = state
) do
schedule_run()

{:ok, predictions} = fetch_predictions_fn.(fetch_params)
jzimbel-mbta marked this conversation as resolved.
Show resolved Hide resolved
next_train_prediction = List.first(predictions)
crowding_levels = Enum.map_join(prediction.vehicle.carriages, ",", & &1.occupancy_status)
jzimbel-mbta marked this conversation as resolved.
Show resolved Hide resolved

cond do
# A car's crowding level changed. Log it and shutdown the process.
original_crowding_levels != crowding_levels ->
Logger.info(
"[train_crowding car_crowding_class_change] screen_id=#{screen_id} triptych_pane=#{triptych_pane} trip_id=#{prediction.trip.id} original_crowding_levels=#{original_crowding_levels} car_crowding_levels=#{crowding_levels}"
)

{:stop, :shutdown, state}

# The train is now stopped at the current station and no crowding level changed. Shut down the process without logging.
Prediction.vehicle_status(next_train_prediction) == :stopped_at and
next_train_prediction |> Prediction.stop_for_vehicle() |> fetch_parent_stop_id_fn.() ==
train_crowding_config.station_id ->
{:stop, :shutdown, state}

# Still more work to do.
true ->
{:noreply, state}
end
end

defp schedule_run do
Process.send_after(self(), :run, 2000)
end
end
9 changes: 9 additions & 0 deletions lib/screens/util.ex
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,13 @@ defmodule Screens.Util do
def get_service_date_tomorrow(now) do
Date.add(get_service_date_today(now), 1)
end

def translate_carriage_occupancy_status(:no_data_available), do: :no_data
def translate_carriage_occupancy_status(:many_seats_available), do: :not_crowded
def translate_carriage_occupancy_status(:few_seats_available), do: :not_crowded
def translate_carriage_occupancy_status(:standing_room_only), do: :some_crowding
def translate_carriage_occupancy_status(:crushed_standing_room_only), do: :crowded
def translate_carriage_occupancy_status(:full), do: :crowded
def translate_carriage_occupancy_status(:not_accepting_passengers), do: :closed
def translate_carriage_occupancy_status(_), do: nil
end
48 changes: 40 additions & 8 deletions lib/screens/v2/candidate_generator/widgets/train_crowding.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ defmodule Screens.V2.CandidateGenerator.Widgets.TrainCrowding do
alias Screens.Config.V2.{TrainCrowding, Triptych}
alias Screens.Predictions.Prediction
alias Screens.Stops.Stop
alias Screens.Util
alias Screens.V2.LocalizedAlert
alias Screens.V2.WidgetInstance.TrainCrowding, as: CrowdingWidget

Expand Down Expand Up @@ -70,7 +71,15 @@ defmodule Screens.V2.CandidateGenerator.Widgets.TrainCrowding do
train_crowding.station_id and
next_train_prediction.vehicle.carriages != [] and
not any_alert_makes_this_a_terminal?(alerts, location_context) do
log_crowding_info(next_train_prediction, logging_options)
_ =
log_crowding_info(
next_train_prediction,
logging_options,
train_crowding,
fetch_predictions_fn,
fetch_parent_stop_id_fn,
params
)

[
%CrowdingWidget{
Expand Down Expand Up @@ -102,17 +111,40 @@ defmodule Screens.V2.CandidateGenerator.Widgets.TrainCrowding do
LocalizedAlert.location(localized_alert) in [:boundary_downstream, :boundary_upstream]
end

defp log_crowding_info(prediction, %{
is_real_screen: true,
screen_id: screen_id,
triptych_pane: triptych_pane
}) do
crowding_levels = Enum.map_join(prediction.vehicle.carriages, ",", & &1.occupancy_status)
defp log_crowding_info(
prediction,
%{
is_real_screen: true,
screen_id: screen_id,
triptych_pane: triptych_pane
} = logging_options,
train_crowding_config,
fetch_predictions_fn,
fetch_parent_stop_id_fn,
fetch_params
) do
crowding_levels =
Enum.map_join(
prediction.vehicle.carriages,
",",
&Util.translate_carriage_occupancy_status(&1.occupancy_status)
)

Logger.info(
"[train_crowding car_crowding_info] screen_id=#{screen_id} triptych_pane=#{triptych_pane} trip_id=#{prediction.trip.id} car_crowding_levels=#{crowding_levels}"
)

_ =
Screens.OlCrowding.DynamicSupervisor.start_logger(
crowding_levels,
prediction,
logging_options,
train_crowding_config,
fetch_predictions_fn,
fetch_parent_stop_id_fn,
fetch_params
)
end

defp log_crowding_info(_, _), do: :ok
defp log_crowding_info(_, _, _, _, _, _), do: :ok
end
11 changes: 2 additions & 9 deletions lib/screens/v2/widget_instance/train_crowding.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ defmodule Screens.V2.WidgetInstance.TrainCrowding do
alias Screens.Config.Screen
alias Screens.Config.V2.Triptych
alias Screens.Predictions.Prediction
alias Screens.Util

defstruct screen: nil,
prediction: nil,
Expand Down Expand Up @@ -58,15 +59,7 @@ defmodule Screens.V2.WidgetInstance.TrainCrowding do
defp serialize_carriages(nil), do: nil

defp serialize_carriages(carriages),
do: Enum.map(carriages, fn car -> serialize_occupancy_status(car.occupancy_status) end)

defp serialize_occupancy_status(:no_data_available), do: :no_data
defp serialize_occupancy_status(:many_seats_available), do: :not_crowded
defp serialize_occupancy_status(:few_seats_available), do: :not_crowded
defp serialize_occupancy_status(:standing_room_only), do: :some_crowding
defp serialize_occupancy_status(:crushed_standing_room_only), do: :crowded
defp serialize_occupancy_status(:full), do: :crowded
defp serialize_occupancy_status(:not_accepting_passengers), do: :closed
do: Enum.map(carriages, &Util.translate_carriage_occupancy_status(&1.occupancy_status))

def priority(_instance), do: [1]

Expand Down
Loading