chore: fixed character updates issue

This commit is contained in:
Dmitry Popov
2025-11-17 13:37:30 +01:00
parent cb4dba8dc2
commit 4dfa83bd30
3 changed files with 91 additions and 48 deletions

View File

@@ -1,6 +1,8 @@
defmodule WandererApp.CachedInfo do defmodule WandererApp.CachedInfo do
require Logger require Logger
alias WandererAppWeb.Helpers.APIUtils
def run(_arg) do def run(_arg) do
:ok = cache_trig_systems() :ok = cache_trig_systems()
end end
@@ -37,6 +39,8 @@ defmodule WandererApp.CachedInfo do
end end
def get_system_static_info(solar_system_id) do def get_system_static_info(solar_system_id) do
{:ok, solar_system_id} = APIUtils.parse_int(solar_system_id)
case Cachex.get(:system_static_info_cache, solar_system_id) do case Cachex.get(:system_static_info_cache, solar_system_id) do
{:ok, nil} -> {:ok, nil} ->
case WandererApp.Api.MapSolarSystem.read() do case WandererApp.Api.MapSolarSystem.read() do

View File

@@ -505,59 +505,96 @@ defmodule WandererApp.Map.Server.SystemsImpl do
:ok :ok
_ -> _ ->
{:ok, solar_system_info} = WandererApp.CachedInfo.get_system_static_info(location.solar_system_id)
WandererApp.CachedInfo.get_system_static_info(location.solar_system_id)
# Use upsert instead of create - handles race conditions gracefully
WandererApp.MapSystemRepo.upsert(%{
map_id: map_id,
solar_system_id: location.solar_system_id,
name: solar_system_info.solar_system_name,
position_x: position.x,
position_y: position.y
})
|> case do |> case do
{:ok, system} -> {:ok, solar_system_info} ->
# System was either created or updated - both cases are success # Use upsert instead of create - handles race conditions gracefully
@ddrt.insert( WandererApp.MapSystemRepo.upsert(%{
{system.solar_system_id, map_id: map_id,
WandererApp.Map.PositionCalculator.get_system_bounding_rect(system)}, solar_system_id: location.solar_system_id,
rtree_name name: solar_system_info.solar_system_name,
) position_x: position.x,
position_y: position.y
WandererApp.Cache.put(
"map_#{map_id}:system_#{system.id}:last_activity",
DateTime.utc_now(),
ttl: @system_inactive_timeout
)
WandererApp.Map.add_system(map_id, system)
Impl.broadcast!(map_id, :add_system, system)
# ADDITIVE: Also broadcast to external event system (webhooks/WebSocket)
WandererApp.ExternalEvents.broadcast(map_id, :add_system, %{
solar_system_id: system.solar_system_id,
name: system.name,
position_x: system.position_x,
position_y: system.position_y
}) })
|> case do
{:ok, system} ->
# System was either created or updated - both cases are success
@ddrt.insert(
{system.solar_system_id,
WandererApp.Map.PositionCalculator.get_system_bounding_rect(system)},
rtree_name
)
:telemetry.execute( WandererApp.Cache.put(
[:wanderer_app, :map, :system_addition, :complete], "map_#{map_id}:system_#{system.id}:last_activity",
%{system_time: System.system_time()}, DateTime.utc_now(),
%{ ttl: @system_inactive_timeout
map_id: map_id, )
solar_system_id: system.solar_system_id,
system_id: system.id,
operation: :upsert
}
)
:ok WandererApp.Map.add_system(map_id, system)
Impl.broadcast!(map_id, :add_system, system)
# ADDITIVE: Also broadcast to external event system (webhooks/WebSocket)
WandererApp.ExternalEvents.broadcast(map_id, :add_system, %{
solar_system_id: system.solar_system_id,
name: system.name,
position_x: system.position_x,
position_y: system.position_y
})
:telemetry.execute(
[:wanderer_app, :map, :system_addition, :complete],
%{system_time: System.system_time()},
%{
map_id: map_id,
solar_system_id: system.solar_system_id,
system_id: system.id,
operation: :upsert
}
)
:ok
{:error, error} = result ->
Logger.warning(
"[CharacterTracking] Failed to upsert system #{location.solar_system_id} on map #{map_id}: #{inspect(error, pretty: true)}"
)
:telemetry.execute(
[:wanderer_app, :map, :system_addition, :error],
%{system_time: System.system_time()},
%{
map_id: map_id,
solar_system_id: location.solar_system_id,
error: error,
reason: :db_upsert_failed
}
)
result
error ->
Logger.warning(
"[CharacterTracking] Failed to upsert system #{location.solar_system_id} on map #{map_id}: #{inspect(error, pretty: true)}"
)
:telemetry.execute(
[:wanderer_app, :map, :system_addition, :error],
%{system_time: System.system_time()},
%{
map_id: map_id,
solar_system_id: location.solar_system_id,
error: error,
reason: :db_upsert_failed_unexpected
}
)
{:error, error}
end
{:error, error} = result -> {:error, error} = result ->
Logger.warning( Logger.warning(
"[CharacterTracking] Failed to upsert system #{location.solar_system_id} on map #{map_id}: #{inspect(error, pretty: true)}" "[CharacterTracking] Failed to add system #{inspect(location.solar_system_id)} on map #{map_id}: #{inspect(error, pretty: true)}"
) )
:telemetry.execute( :telemetry.execute(
@@ -575,7 +612,7 @@ defmodule WandererApp.Map.Server.SystemsImpl do
error -> error ->
Logger.warning( Logger.warning(
"[CharacterTracking] Failed to upsert system #{location.solar_system_id} on map #{map_id}: #{inspect(error, pretty: true)}" "[CharacterTracking] Failed to add system #{inspect(location.solar_system_id)} on map #{map_id}: #{inspect(error, pretty: true)}"
) )
:telemetry.execute( :telemetry.execute(

View File

@@ -74,8 +74,10 @@ defmodule WandererAppWeb.Helpers.APIUtils do
end end
@spec parse_int(binary() | integer()) :: {:ok, integer()} | {:error, String.t()} @spec parse_int(binary() | integer()) :: {:ok, integer()} | {:error, String.t()}
def parse_int(nil), do: {:ok, nil}
def parse_int(str) when is_binary(str) do def parse_int(str) when is_binary(str) do
Logger.debug("Parsing integer from: #{inspect(str)}") Logger.debug(fn -> "Parsing integer from: #{inspect(str)}" end)
case Integer.parse(str) do case Integer.parse(str) do
{num, ""} -> {:ok, num} {num, ""} -> {:ok, num}