Packages
A library for generating fake GPS data or load GPS from GPX file/string using for dev/test. The library generates GPSs for simulating a route and scalable for test workload.
Current section
Files
Jump to
Current section
Files
lib/worker_base.ex
defmodule LocationSimulator.WorkerBase do
@moduledoc """
Shared helpers for `Worker` and `WorkerGpx`.
Provides child spec generation, process linking, registry management,
timestamp utilities, and the start/stop event lifecycle.
"""
require Logger
# ── OTP boilerplate ────────────────────────────────────────────────────────
@doc "Returns a temporary `DynamicSupervisor`-compatible child spec."
@spec child_spec(module(), map()) :: map()
def child_spec(module, opts) when is_map(opts) do
%{
id: Map.get(opts, :id, module),
start: {module, :start_link, [opts]},
type: :worker,
restart: Map.get(opts, :restart, :temporary),
shutdown: Map.get(opts, :shutdown, :brutal_kill)
}
end
@doc "Spawns `module.init/1` linked to the calling process."
@spec start_link(module(), map()) :: {:ok, pid()}
def start_link(module, arg) do
pid = spawn_link(module, :init, [arg])
{:ok, pid}
end
# ── Registry ───────────────────────────────────────────────────────────────
@doc "Registers the current process under `group_id` when present in config."
@spec maybe_register(map()) :: :ok
def maybe_register(%{group_id: group_id, id: id}) do
Registry.register(LocationSimulator.Registry, group_id, id)
:ok
end
def maybe_register(_config), do: :ok
# ── Lifecycle events ───────────────────────────────────────────────────────
@doc """
Fires `callback.start/2`.
Returns the (possibly updated) config on success, raises on error.
"""
@spec fire_start!(map(), map()) :: map()
def fire_start!(%{callback: mod} = config, state) do
id = Map.get(config, :id, self())
Logger.debug("Worker #{inspect(id)}: firing start event")
case mod.start(config, state) do
{:ok, new_config} ->
new_config
{:error, reason} ->
raise "Worker #{inspect(id)}: start callback failed – #{inspect(reason)}"
end
end
@doc """
Fires `callback.stop/2`, logs completion, and returns the updated config.
"""
@spec fire_stop!(map(), map()) :: map()
def fire_stop!(%{callback: mod} = config, state) do
id = Map.get(config, :id, self())
Logger.debug("Worker #{inspect(id)}: firing stop event")
stop_time = unix_seconds()
state = Map.put(state, :stop_time, stop_time)
new_config =
case mod.stop(config, state) do
{:ok, cfg} ->
cfg
{:error, reason} ->
raise "Worker #{inspect(id)}: stop callback failed – #{inspect(reason)}"
end
elapsed = stop_time - state.start_time
Logger.debug(
"Worker #{inspect(id)} DONE – elapsed: #{elapsed}s, " <>
"success: #{state.success}, failed: #{state.failed}, error: #{state.error}"
)
new_config
end
# ── Utilities ──────────────────────────────────────────────────────────────
@doc "Current Unix time in seconds."
@spec unix_seconds() :: non_neg_integer()
def unix_seconds, do: :os.system_time(:seconds)
@doc "Initial worker statistics map."
@spec init_state() :: map()
def init_state do
%{start_time: unix_seconds(), success: 0, failed: 0, error: 0}
end
end