mirror of
https://github.com/wanderer-industries/wanderer
synced 2025-12-08 16:56:03 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2f5f14c44 | ||
|
|
0b7c3588d5 | ||
|
|
a51fac5736 | ||
|
|
726c3d0704 | ||
|
|
8dd564dbd0 | ||
|
|
e33c65cddc | ||
|
|
f2fbd2ead0 | ||
|
|
123a2e45eb | ||
|
|
f8d2d9c680 | ||
|
|
9dcbef9a79 |
27
CHANGELOG.md
27
CHANGELOG.md
@@ -2,6 +2,33 @@
|
||||
|
||||
<!-- changelog -->
|
||||
|
||||
## [v1.77.14](https://github.com/wanderer-industries/wanderer/compare/v1.77.13...v1.77.14) (2025-09-08)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Fixed issue with loading connection info
|
||||
|
||||
## [v1.77.13](https://github.com/wanderer-industries/wanderer/compare/v1.77.12...v1.77.13) (2025-09-07)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Updated character tracking, added an extra check for offline characters to reduce errors
|
||||
|
||||
## [v1.77.12](https://github.com/wanderer-industries/wanderer/compare/v1.77.11...v1.77.12) (2025-09-07)
|
||||
|
||||
|
||||
|
||||
|
||||
### Bug Fixes:
|
||||
|
||||
* Decreased character tracking grace period
|
||||
|
||||
## [v1.77.11](https://github.com/wanderer-industries/wanderer/compare/v1.77.10...v1.77.11) (2025-09-07)
|
||||
|
||||
|
||||
|
||||
@@ -37,13 +37,14 @@ defmodule WandererApp.Character.Tracker do
|
||||
}
|
||||
|
||||
@pause_tracking_timeout :timer.minutes(60 * 10)
|
||||
@offline_timeout :timer.minutes(10)
|
||||
@offline_timeout :timer.minutes(5)
|
||||
@online_error_timeout :timer.minutes(10)
|
||||
@ship_error_timeout :timer.minutes(10)
|
||||
@location_error_timeout :timer.minutes(10)
|
||||
@online_forbidden_ttl :timer.seconds(7)
|
||||
@offline_check_delay_ttl :timer.seconds(15)
|
||||
@online_limit_ttl :timer.seconds(7)
|
||||
@forbidden_ttl :timer.seconds(5)
|
||||
@forbidden_ttl :timer.seconds(10)
|
||||
@limit_ttl :timer.seconds(5)
|
||||
@location_limit_ttl :timer.seconds(1)
|
||||
@pubsub_client Application.compile_env(:wanderer_app, :pubsub_client)
|
||||
@@ -71,18 +72,19 @@ defmodule WandererApp.Character.Tracker do
|
||||
WandererApp.Cache.lookup!("character:#{character_id}:last_online_time")
|
||||
|> case do
|
||||
nil ->
|
||||
WandererApp.Cache.insert(
|
||||
"character:#{character_id}:last_online_time",
|
||||
DateTime.utc_now()
|
||||
)
|
||||
|
||||
:ok
|
||||
|
||||
last_online_time ->
|
||||
duration = DateTime.diff(DateTime.utc_now(), last_online_time, :millisecond)
|
||||
|
||||
if duration >= @offline_timeout do
|
||||
pause_tracking(character_id)
|
||||
WandererApp.Character.update_character(character_id, %{online: false})
|
||||
|
||||
WandererApp.Character.update_character_state(character_id, %{
|
||||
is_online: false
|
||||
})
|
||||
|
||||
WandererApp.Cache.delete("character:#{character_id}:last_online_time")
|
||||
|
||||
:ok
|
||||
else
|
||||
@@ -186,7 +188,9 @@ defmodule WandererApp.Character.Tracker do
|
||||
|> WandererApp.Character.get_character_state!()
|
||||
|> update_online()
|
||||
|
||||
def update_online(%{track_online: true, character_id: character_id} = character_state) do
|
||||
def update_online(
|
||||
%{track_online: true, character_id: character_id, is_online: is_online} = character_state
|
||||
) do
|
||||
case WandererApp.Character.get_character(character_id) do
|
||||
{:ok, %{eve_id: eve_id, access_token: access_token, tracking_pool: tracking_pool}}
|
||||
when not is_nil(access_token) ->
|
||||
@@ -197,8 +201,6 @@ defmodule WandererApp.Character.Tracker do
|
||||
{:error, :skipped}
|
||||
|
||||
_ ->
|
||||
# Monitor cache for potential evictions before ESI call
|
||||
|
||||
case WandererApp.Esi.get_character_online(eve_id,
|
||||
access_token: access_token,
|
||||
character_id: character_id
|
||||
@@ -211,70 +213,67 @@ defmodule WandererApp.Character.Tracker do
|
||||
"character:#{character_id}:last_online_time",
|
||||
DateTime.utc_now()
|
||||
)
|
||||
|
||||
WandererApp.Cache.delete("character:#{character_id}:online_forbidden")
|
||||
else
|
||||
# Delay next online updates for offline characters
|
||||
WandererApp.Cache.put(
|
||||
"character:#{character_id}:online_forbidden",
|
||||
true,
|
||||
ttl: @offline_check_delay_ttl
|
||||
)
|
||||
end
|
||||
|
||||
if online.online == true && online.online != is_online do
|
||||
WandererApp.Cache.delete("character:#{character_id}:ship_error_time")
|
||||
WandererApp.Cache.delete("character:#{character_id}:location_error_time")
|
||||
WandererApp.Cache.delete("character:#{character_id}:info_forbidden")
|
||||
WandererApp.Cache.delete("character:#{character_id}:ship_forbidden")
|
||||
WandererApp.Cache.delete("character:#{character_id}:location_forbidden")
|
||||
WandererApp.Cache.delete("character:#{character_id}:wallet_forbidden")
|
||||
WandererApp.Cache.delete("character:#{character_id}:corporation_info_forbidden")
|
||||
end
|
||||
|
||||
WandererApp.Cache.delete("character:#{character_id}:online_forbidden")
|
||||
WandererApp.Cache.delete("character:#{character_id}:online_error_time")
|
||||
WandererApp.Cache.delete("character:#{character_id}:ship_error_time")
|
||||
WandererApp.Cache.delete("character:#{character_id}:location_error_time")
|
||||
WandererApp.Cache.delete("character:#{character_id}:info_forbidden")
|
||||
WandererApp.Cache.delete("character:#{character_id}:ship_forbidden")
|
||||
WandererApp.Cache.delete("character:#{character_id}:location_forbidden")
|
||||
WandererApp.Cache.delete("character:#{character_id}:wallet_forbidden")
|
||||
|
||||
try do
|
||||
WandererApp.Character.update_character(character_id, online)
|
||||
rescue
|
||||
error ->
|
||||
Logger.error("DB_ERROR: Failed to update character in database",
|
||||
character_id: character_id,
|
||||
error: inspect(error),
|
||||
operation: "update_character_online"
|
||||
)
|
||||
if online.online != is_online do
|
||||
try do
|
||||
WandererApp.Character.update_character(character_id, online)
|
||||
rescue
|
||||
error ->
|
||||
Logger.error("DB_ERROR: Failed to update character in database",
|
||||
character_id: character_id,
|
||||
error: inspect(error),
|
||||
operation: "update_character_online"
|
||||
)
|
||||
|
||||
# Re-raise to maintain existing error handling
|
||||
reraise error, __STACKTRACE__
|
||||
end
|
||||
# Re-raise to maintain existing error handling
|
||||
reraise error, __STACKTRACE__
|
||||
end
|
||||
|
||||
update = %{
|
||||
character_state
|
||||
| is_online: online.online,
|
||||
track_ship: online.online,
|
||||
track_location: online.online
|
||||
}
|
||||
try do
|
||||
WandererApp.Character.update_character_state(character_id, %{
|
||||
character_state
|
||||
| is_online: online.online,
|
||||
track_ship: online.online,
|
||||
track_location: online.online
|
||||
})
|
||||
rescue
|
||||
error ->
|
||||
Logger.error("DB_ERROR: Failed to update character state in database",
|
||||
character_id: character_id,
|
||||
error: inspect(error),
|
||||
operation: "update_character_state"
|
||||
)
|
||||
|
||||
try do
|
||||
WandererApp.Character.update_character_state(character_id, update)
|
||||
rescue
|
||||
error ->
|
||||
Logger.error("DB_ERROR: Failed to update character state in database",
|
||||
character_id: character_id,
|
||||
error: inspect(error),
|
||||
operation: "update_character_state"
|
||||
)
|
||||
|
||||
# Re-raise to maintain existing error handling
|
||||
reraise error, __STACKTRACE__
|
||||
# Re-raise to maintain existing error handling
|
||||
reraise error, __STACKTRACE__
|
||||
end
|
||||
end
|
||||
|
||||
:ok
|
||||
|
||||
{:error, error} when error in [:forbidden, :not_found, :timeout] ->
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute([:wanderer_app, :esi, :error], %{count: 1}, %{
|
||||
endpoint: "character_online",
|
||||
error_type: error,
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
})
|
||||
|
||||
Logger.warning("ESI_ERROR: Character online tracking failed #{inspect(error)}",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
error_type: error,
|
||||
endpoint: "character_online"
|
||||
)
|
||||
|
||||
WandererApp.Cache.put(
|
||||
"character:#{character_id}:online_forbidden",
|
||||
true,
|
||||
@@ -301,28 +300,6 @@ defmodule WandererApp.Character.Tracker do
|
||||
remaining =
|
||||
Map.get(headers, "x-esi-error-limit-remain", ["unknown"]) |> List.first()
|
||||
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute(
|
||||
[:wanderer_app, :esi, :rate_limited],
|
||||
%{
|
||||
reset_duration: reset_timeout,
|
||||
count: 1
|
||||
},
|
||||
%{
|
||||
endpoint: "character_online",
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
}
|
||||
)
|
||||
|
||||
Logger.warning("ESI_RATE_LIMITED: Character online tracking rate limited",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
endpoint: "character_online",
|
||||
reset_seconds: reset_seconds,
|
||||
remaining_requests: remaining
|
||||
)
|
||||
|
||||
WandererApp.Cache.put(
|
||||
"character:#{character_id}:online_forbidden",
|
||||
true,
|
||||
@@ -332,15 +309,7 @@ defmodule WandererApp.Character.Tracker do
|
||||
{:error, :skipped}
|
||||
|
||||
{:error, error} ->
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute([:wanderer_app, :esi, :error], %{count: 1}, %{
|
||||
endpoint: "character_online",
|
||||
error_type: error,
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
})
|
||||
|
||||
Logger.error("ESI_ERROR: Character online tracking failed",
|
||||
Logger.error("ESI_ERROR: Character online tracking failed: #{inspect(error)}",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
error_type: error,
|
||||
@@ -417,21 +386,6 @@ defmodule WandererApp.Character.Tracker do
|
||||
:ok
|
||||
|
||||
{:error, error} when error in [:forbidden, :not_found, :timeout] ->
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute([:wanderer_app, :esi, :error], %{count: 1}, %{
|
||||
endpoint: "character_info",
|
||||
error_type: error,
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
})
|
||||
|
||||
Logger.warning("ESI_ERROR: Character info tracking failed",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
error_type: error,
|
||||
endpoint: "character_info"
|
||||
)
|
||||
|
||||
WandererApp.Cache.put(
|
||||
"character:#{character_id}:info_forbidden",
|
||||
true,
|
||||
@@ -443,33 +397,6 @@ defmodule WandererApp.Character.Tracker do
|
||||
{:error, :error_limited, headers} ->
|
||||
reset_timeout = get_reset_timeout(headers)
|
||||
|
||||
reset_seconds =
|
||||
Map.get(headers, "x-esi-error-limit-reset", ["unknown"]) |> List.first()
|
||||
|
||||
remaining = Map.get(headers, "x-esi-error-limit-remain", ["unknown"]) |> List.first()
|
||||
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute(
|
||||
[:wanderer_app, :esi, :rate_limited],
|
||||
%{
|
||||
reset_duration: reset_timeout,
|
||||
count: 1
|
||||
},
|
||||
%{
|
||||
endpoint: "character_info",
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
}
|
||||
)
|
||||
|
||||
Logger.warning("ESI_RATE_LIMITED: Character info tracking rate limited",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
endpoint: "character_info",
|
||||
reset_seconds: reset_seconds,
|
||||
remaining_requests: remaining
|
||||
)
|
||||
|
||||
WandererApp.Cache.put(
|
||||
"character:#{character_id}:info_forbidden",
|
||||
true,
|
||||
@@ -479,21 +406,13 @@ defmodule WandererApp.Character.Tracker do
|
||||
{:error, :error_limited}
|
||||
|
||||
{:error, error} ->
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute([:wanderer_app, :esi, :error], %{count: 1}, %{
|
||||
endpoint: "character_info",
|
||||
error_type: error,
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
})
|
||||
|
||||
WandererApp.Cache.put(
|
||||
"character:#{character_id}:info_forbidden",
|
||||
true,
|
||||
ttl: @forbidden_ttl
|
||||
)
|
||||
|
||||
Logger.error("ESI_ERROR: Character info tracking failed",
|
||||
Logger.error("ESI_ERROR: Character info tracking failed: #{inspect(error)}",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
error_type: error,
|
||||
@@ -540,21 +459,6 @@ defmodule WandererApp.Character.Tracker do
|
||||
:ok
|
||||
|
||||
{:error, error} when error in [:forbidden, :not_found, :timeout] ->
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute([:wanderer_app, :esi, :error], %{count: 1}, %{
|
||||
endpoint: "character_ship",
|
||||
error_type: error,
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
})
|
||||
|
||||
Logger.warning("ESI_ERROR: Character ship tracking failed",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
error_type: error,
|
||||
endpoint: "character_ship"
|
||||
)
|
||||
|
||||
WandererApp.Cache.put(
|
||||
"character:#{character_id}:ship_forbidden",
|
||||
true,
|
||||
@@ -573,34 +477,6 @@ defmodule WandererApp.Character.Tracker do
|
||||
{:error, :error_limited, headers} ->
|
||||
reset_timeout = get_reset_timeout(headers)
|
||||
|
||||
reset_seconds =
|
||||
Map.get(headers, "x-esi-error-limit-reset", ["unknown"]) |> List.first()
|
||||
|
||||
remaining =
|
||||
Map.get(headers, "x-esi-error-limit-remain", ["unknown"]) |> List.first()
|
||||
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute(
|
||||
[:wanderer_app, :esi, :rate_limited],
|
||||
%{
|
||||
reset_duration: reset_timeout,
|
||||
count: 1
|
||||
},
|
||||
%{
|
||||
endpoint: "character_ship",
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
}
|
||||
)
|
||||
|
||||
Logger.warning("ESI_RATE_LIMITED: Character ship tracking rate limited",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
endpoint: "character_ship",
|
||||
reset_seconds: reset_seconds,
|
||||
remaining_requests: remaining
|
||||
)
|
||||
|
||||
WandererApp.Cache.put(
|
||||
"character:#{character_id}:ship_forbidden",
|
||||
true,
|
||||
@@ -610,15 +486,7 @@ defmodule WandererApp.Character.Tracker do
|
||||
{:error, :error_limited}
|
||||
|
||||
{:error, error} ->
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute([:wanderer_app, :esi, :error], %{count: 1}, %{
|
||||
endpoint: "character_ship",
|
||||
error_type: error,
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
})
|
||||
|
||||
Logger.error("ESI_ERROR: Character ship tracking failed",
|
||||
Logger.error("ESI_ERROR: Character ship tracking failed: #{inspect(error)}",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
error_type: error,
|
||||
@@ -641,14 +509,6 @@ defmodule WandererApp.Character.Tracker do
|
||||
{:error, error}
|
||||
|
||||
_ ->
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute([:wanderer_app, :esi, :error], %{count: 1}, %{
|
||||
endpoint: "character_ship",
|
||||
error_type: "wrong_response",
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
})
|
||||
|
||||
Logger.error("ESI_ERROR: Character ship tracking failed - wrong response",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
@@ -711,14 +571,6 @@ defmodule WandererApp.Character.Tracker do
|
||||
:ok
|
||||
|
||||
{:error, error} when error in [:forbidden, :not_found, :timeout] ->
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute([:wanderer_app, :esi, :error], %{count: 1}, %{
|
||||
endpoint: "character_location",
|
||||
error_type: error,
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
})
|
||||
|
||||
Logger.warning("ESI_ERROR: Character location tracking failed",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
@@ -740,34 +592,6 @@ defmodule WandererApp.Character.Tracker do
|
||||
{:error, :error_limited, headers} ->
|
||||
reset_timeout = get_reset_timeout(headers, @location_limit_ttl)
|
||||
|
||||
reset_seconds =
|
||||
Map.get(headers, "x-esi-error-limit-reset", ["unknown"]) |> List.first()
|
||||
|
||||
remaining =
|
||||
Map.get(headers, "x-esi-error-limit-remain", ["unknown"]) |> List.first()
|
||||
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute(
|
||||
[:wanderer_app, :esi, :rate_limited],
|
||||
%{
|
||||
reset_duration: reset_timeout,
|
||||
count: 1
|
||||
},
|
||||
%{
|
||||
endpoint: "character_location",
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
}
|
||||
)
|
||||
|
||||
Logger.warning("ESI_RATE_LIMITED: Character location tracking rate limited",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
endpoint: "character_location",
|
||||
reset_seconds: reset_seconds,
|
||||
remaining_requests: remaining
|
||||
)
|
||||
|
||||
WandererApp.Cache.put(
|
||||
"character:#{character_id}:location_forbidden",
|
||||
true,
|
||||
@@ -777,15 +601,7 @@ defmodule WandererApp.Character.Tracker do
|
||||
{:error, :error_limited}
|
||||
|
||||
{:error, error} ->
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute([:wanderer_app, :esi, :error], %{count: 1}, %{
|
||||
endpoint: "character_location",
|
||||
error_type: error,
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
})
|
||||
|
||||
Logger.error("ESI_ERROR: Character location tracking failed",
|
||||
Logger.error("ESI_ERROR: Character location tracking failed: #{inspect(error)}",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
error_type: error,
|
||||
@@ -804,14 +620,6 @@ defmodule WandererApp.Character.Tracker do
|
||||
{:error, :skipped}
|
||||
|
||||
_ ->
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute([:wanderer_app, :esi, :error], %{count: 1}, %{
|
||||
endpoint: "character_location",
|
||||
error_type: "wrong_response",
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
})
|
||||
|
||||
Logger.error("ESI_ERROR: Character location tracking failed - wrong response",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
@@ -873,14 +681,6 @@ defmodule WandererApp.Character.Tracker do
|
||||
:ok
|
||||
|
||||
{:error, error} when error in [:forbidden, :not_found, :timeout] ->
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute([:wanderer_app, :esi, :error], %{count: 1}, %{
|
||||
endpoint: "character_wallet",
|
||||
error_type: error,
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
})
|
||||
|
||||
Logger.warning("ESI_ERROR: Character wallet tracking failed",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
@@ -899,34 +699,6 @@ defmodule WandererApp.Character.Tracker do
|
||||
{:error, :error_limited, headers} ->
|
||||
reset_timeout = get_reset_timeout(headers)
|
||||
|
||||
reset_seconds =
|
||||
Map.get(headers, "x-esi-error-limit-reset", ["unknown"]) |> List.first()
|
||||
|
||||
remaining =
|
||||
Map.get(headers, "x-esi-error-limit-remain", ["unknown"]) |> List.first()
|
||||
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute(
|
||||
[:wanderer_app, :esi, :rate_limited],
|
||||
%{
|
||||
reset_duration: reset_timeout,
|
||||
count: 1
|
||||
},
|
||||
%{
|
||||
endpoint: "character_wallet",
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
}
|
||||
)
|
||||
|
||||
Logger.warning("ESI_RATE_LIMITED: Character wallet tracking rate limited",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
endpoint: "character_wallet",
|
||||
reset_seconds: reset_seconds,
|
||||
remaining_requests: remaining
|
||||
)
|
||||
|
||||
WandererApp.Cache.put(
|
||||
"character:#{character_id}:wallet_forbidden",
|
||||
true,
|
||||
@@ -936,15 +708,7 @@ defmodule WandererApp.Character.Tracker do
|
||||
{:error, :skipped}
|
||||
|
||||
{:error, error} ->
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute([:wanderer_app, :esi, :error], %{count: 1}, %{
|
||||
endpoint: "character_wallet",
|
||||
error_type: error,
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
})
|
||||
|
||||
Logger.error("ESI_ERROR: Character wallet tracking failed",
|
||||
Logger.error("ESI_ERROR: Character wallet tracking failed: #{inspect(error)}",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
error_type: error,
|
||||
@@ -960,15 +724,7 @@ defmodule WandererApp.Character.Tracker do
|
||||
{:error, :skipped}
|
||||
|
||||
error ->
|
||||
# Emit telemetry for tracking
|
||||
:telemetry.execute([:wanderer_app, :esi, :error], %{count: 1}, %{
|
||||
endpoint: "character_wallet",
|
||||
error_type: error,
|
||||
tracking_pool: tracking_pool,
|
||||
character_id: character_id
|
||||
})
|
||||
|
||||
Logger.error("ESI_ERROR: Character wallet tracking failed",
|
||||
Logger.error("ESI_ERROR: Character wallet tracking failed: #{inspect(error)}",
|
||||
character_id: character_id,
|
||||
tracking_pool: tracking_pool,
|
||||
error_type: error,
|
||||
@@ -1073,6 +829,7 @@ defmodule WandererApp.Character.Tracker do
|
||||
)
|
||||
when old_corporation_id != corporation_id do
|
||||
(WandererApp.Cache.has_key?("character:#{character_id}:online_forbidden") ||
|
||||
WandererApp.Cache.has_key?("character:#{character_id}:corporation_info_forbidden") ||
|
||||
WandererApp.Cache.has_key?("character:#{character_id}:tracking_paused"))
|
||||
|> case do
|
||||
true ->
|
||||
@@ -1112,6 +869,17 @@ defmodule WandererApp.Character.Tracker do
|
||||
state
|
||||
|> Map.merge(%{corporation_id: corporation_id})
|
||||
|
||||
{:error, :error_limited, headers} ->
|
||||
reset_timeout = get_reset_timeout(headers)
|
||||
|
||||
WandererApp.Cache.put(
|
||||
"character:#{character_id}:corporation_info_forbidden",
|
||||
true,
|
||||
ttl: reset_timeout
|
||||
)
|
||||
|
||||
state
|
||||
|
||||
error ->
|
||||
Logger.warning(
|
||||
"Failed to get corporation info for character #{character_id}: #{inspect(error)}",
|
||||
|
||||
@@ -13,10 +13,9 @@ defmodule WandererApp.Character.TrackerManager.Impl do
|
||||
}
|
||||
|
||||
@check_start_queue_interval :timer.seconds(1)
|
||||
@garbage_collection_interval :timer.minutes(15)
|
||||
@garbage_collection_interval :timer.minutes(5)
|
||||
@untrack_characters_interval :timer.minutes(5)
|
||||
@inactive_character_timeout :timer.minutes(10)
|
||||
@untrack_character_timeout :timer.minutes(10)
|
||||
@inactive_character_timeout :timer.minutes(5)
|
||||
|
||||
@logger Application.compile_env(:wanderer_app, :logger)
|
||||
|
||||
@@ -116,13 +115,6 @@ defmodule WandererApp.Character.TrackerManager.Impl do
|
||||
end
|
||||
|
||||
def add_to_untrack_queue(map_id, character_id) do
|
||||
if not WandererApp.Cache.has_key?("#{map_id}:#{character_id}:untrack_requested") do
|
||||
WandererApp.Cache.insert(
|
||||
"#{map_id}:#{character_id}:untrack_requested",
|
||||
DateTime.utc_now()
|
||||
)
|
||||
end
|
||||
|
||||
WandererApp.Cache.insert_or_update(
|
||||
"character_untrack_queue",
|
||||
[{map_id, character_id}],
|
||||
@@ -134,8 +126,6 @@ defmodule WandererApp.Character.TrackerManager.Impl do
|
||||
end
|
||||
|
||||
def remove_from_untrack_queue(map_id, character_id) do
|
||||
WandererApp.Cache.delete("#{map_id}:#{character_id}:untrack_requested")
|
||||
|
||||
WandererApp.Cache.insert_or_update(
|
||||
"character_untrack_queue",
|
||||
[],
|
||||
@@ -239,50 +229,32 @@ defmodule WandererApp.Character.TrackerManager.Impl do
|
||||
WandererApp.Cache.lookup!("character_untrack_queue", [])
|
||||
|> Task.async_stream(
|
||||
fn {map_id, character_id} ->
|
||||
untrack_timeout_reached =
|
||||
if WandererApp.Cache.has_key?("#{map_id}:#{character_id}:untrack_requested") do
|
||||
untrack_requested =
|
||||
WandererApp.Cache.lookup!(
|
||||
"#{map_id}:#{character_id}:untrack_requested",
|
||||
DateTime.utc_now()
|
||||
)
|
||||
remove_from_untrack_queue(map_id, character_id)
|
||||
|
||||
duration = DateTime.diff(DateTime.utc_now(), untrack_requested, :millisecond)
|
||||
duration >= @untrack_character_timeout
|
||||
else
|
||||
false
|
||||
end
|
||||
WandererApp.Cache.delete("map:#{map_id}:character:#{character_id}:solar_system_id")
|
||||
WandererApp.Cache.delete("map:#{map_id}:character:#{character_id}:station_id")
|
||||
WandererApp.Cache.delete("map:#{map_id}:character:#{character_id}:structure_id")
|
||||
|
||||
Logger.debug(fn -> "Untrack timeout reached: #{inspect(untrack_timeout_reached)}" end)
|
||||
{:ok, character_state} =
|
||||
WandererApp.Character.Tracker.update_settings(character_id, %{
|
||||
map_id: map_id,
|
||||
track: false
|
||||
})
|
||||
|
||||
if untrack_timeout_reached do
|
||||
remove_from_untrack_queue(map_id, character_id)
|
||||
{:ok, character} = WandererApp.Character.get_character(character_id)
|
||||
|
||||
WandererApp.Cache.delete("map:#{map_id}:character:#{character_id}:solar_system_id")
|
||||
WandererApp.Cache.delete("map:#{map_id}:character:#{character_id}:station_id")
|
||||
WandererApp.Cache.delete("map:#{map_id}:character:#{character_id}:structure_id")
|
||||
{:ok, _updated} =
|
||||
WandererApp.MapCharacterSettingsRepo.update(map_id, character_id, %{
|
||||
ship: character.ship,
|
||||
ship_name: character.ship_name,
|
||||
ship_item_id: character.ship_item_id,
|
||||
solar_system_id: character.solar_system_id,
|
||||
structure_id: character.structure_id,
|
||||
station_id: character.station_id
|
||||
})
|
||||
|
||||
{:ok, character_state} =
|
||||
WandererApp.Character.Tracker.update_settings(character_id, %{
|
||||
map_id: map_id,
|
||||
track: false
|
||||
})
|
||||
|
||||
{:ok, character} = WandererApp.Character.get_character(character_id)
|
||||
|
||||
{:ok, _updated} =
|
||||
WandererApp.MapCharacterSettingsRepo.update(map_id, character_id, %{
|
||||
ship: character.ship,
|
||||
ship_name: character.ship_name,
|
||||
ship_item_id: character.ship_item_id,
|
||||
solar_system_id: character.solar_system_id,
|
||||
structure_id: character.structure_id,
|
||||
station_id: character.station_id
|
||||
})
|
||||
|
||||
WandererApp.Character.update_character_state(character_id, character_state)
|
||||
WandererApp.Map.Server.Impl.broadcast!(map_id, :untrack_character, character_id)
|
||||
end
|
||||
WandererApp.Character.update_character_state(character_id, character_state)
|
||||
WandererApp.Map.Server.Impl.broadcast!(map_id, :untrack_character, character_id)
|
||||
end,
|
||||
max_concurrency: System.schedulers_online(),
|
||||
on_timeout: :kill_task,
|
||||
|
||||
@@ -18,7 +18,7 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
|
||||
@update_location_interval :timer.seconds(1)
|
||||
@update_online_interval :timer.seconds(5)
|
||||
@check_offline_characters_interval :timer.minutes(2)
|
||||
@check_offline_characters_interval :timer.minutes(5)
|
||||
@check_online_errors_interval :timer.minutes(1)
|
||||
@check_ship_errors_interval :timer.minutes(1)
|
||||
@check_location_errors_interval :timer.minutes(1)
|
||||
@@ -124,7 +124,7 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
Process.send_after(self(), :check_online_errors, :timer.seconds(60))
|
||||
Process.send_after(self(), :check_ship_errors, :timer.seconds(90))
|
||||
Process.send_after(self(), :check_location_errors, :timer.seconds(120))
|
||||
# Process.send_after(self(), :check_offline_characters, @check_offline_characters_interval)
|
||||
Process.send_after(self(), :check_offline_characters, @check_offline_characters_interval)
|
||||
Process.send_after(self(), :update_location, 300)
|
||||
Process.send_after(self(), :update_ship, 500)
|
||||
Process.send_after(self(), :update_info, 1500)
|
||||
@@ -176,11 +176,15 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
|
||||
try do
|
||||
characters
|
||||
|> Enum.each(fn character_id ->
|
||||
WandererApp.TaskWrapper.start_link(WandererApp.Character.Tracker, :update_online, [
|
||||
character_id
|
||||
])
|
||||
end)
|
||||
|> Task.async_stream(
|
||||
fn character_id ->
|
||||
WandererApp.Character.Tracker.update_online(character_id)
|
||||
end,
|
||||
max_concurrency: System.schedulers_online(),
|
||||
on_timeout: :kill_task,
|
||||
timeout: :timer.seconds(5)
|
||||
)
|
||||
|> Enum.each(fn _result -> :ok end)
|
||||
rescue
|
||||
e ->
|
||||
Logger.error("""
|
||||
@@ -234,17 +238,7 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
characters
|
||||
|> Task.async_stream(
|
||||
fn character_id ->
|
||||
if WandererApp.Character.can_pause_tracking?(character_id) do
|
||||
WandererApp.TaskWrapper.start_link(
|
||||
WandererApp.Character.Tracker,
|
||||
:check_offline,
|
||||
[
|
||||
character_id
|
||||
]
|
||||
)
|
||||
else
|
||||
:ok
|
||||
end
|
||||
WandererApp.Character.Tracker.check_offline(character_id)
|
||||
end,
|
||||
timeout: :timer.seconds(15),
|
||||
max_concurrency: System.schedulers_online(),
|
||||
@@ -397,11 +391,15 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
|
||||
try do
|
||||
characters
|
||||
|> Enum.each(fn character_id ->
|
||||
WandererApp.TaskWrapper.start_link(WandererApp.Character.Tracker, :update_location, [
|
||||
character_id
|
||||
])
|
||||
end)
|
||||
|> Task.async_stream(
|
||||
fn character_id ->
|
||||
WandererApp.Character.Tracker.update_location(character_id)
|
||||
end,
|
||||
max_concurrency: System.schedulers_online(),
|
||||
on_timeout: :kill_task,
|
||||
timeout: :timer.seconds(5)
|
||||
)
|
||||
|> Enum.each(fn _result -> :ok end)
|
||||
rescue
|
||||
e ->
|
||||
Logger.error("""
|
||||
@@ -434,11 +432,15 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
|
||||
try do
|
||||
characters
|
||||
|> Enum.each(fn character_id ->
|
||||
WandererApp.TaskWrapper.start_link(WandererApp.Character.Tracker, :update_ship, [
|
||||
character_id
|
||||
])
|
||||
end)
|
||||
|> Task.async_stream(
|
||||
fn character_id ->
|
||||
WandererApp.Character.Tracker.update_ship(character_id)
|
||||
end,
|
||||
max_concurrency: System.schedulers_online(),
|
||||
on_timeout: :kill_task,
|
||||
timeout: :timer.seconds(5)
|
||||
)
|
||||
|> Enum.each(fn _result -> :ok end)
|
||||
rescue
|
||||
e ->
|
||||
Logger.error("""
|
||||
@@ -473,9 +475,7 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
characters
|
||||
|> Task.async_stream(
|
||||
fn character_id ->
|
||||
WandererApp.TaskWrapper.start_link(WandererApp.Character.Tracker, :update_info, [
|
||||
character_id
|
||||
])
|
||||
WandererApp.Character.Tracker.update_info(character_id)
|
||||
end,
|
||||
timeout: :timer.seconds(15),
|
||||
max_concurrency: System.schedulers_online(),
|
||||
@@ -519,9 +519,7 @@ defmodule WandererApp.Character.TrackerPool do
|
||||
characters
|
||||
|> Task.async_stream(
|
||||
fn character_id ->
|
||||
WandererApp.TaskWrapper.start_link(WandererApp.Character.Tracker, :update_wallet, [
|
||||
character_id
|
||||
])
|
||||
WandererApp.Character.Tracker.update_wallet(character_id)
|
||||
end,
|
||||
timeout: :timer.seconds(15),
|
||||
max_concurrency: System.schedulers_online(),
|
||||
|
||||
@@ -213,85 +213,100 @@ defmodule WandererApp.Map.Server.CharactersImpl do
|
||||
end
|
||||
|
||||
def update_characters(%{map_id: map_id} = state) do
|
||||
{:ok, presence_character_ids} =
|
||||
WandererApp.Cache.lookup("map_#{map_id}:presence_character_ids", [])
|
||||
try do
|
||||
{:ok, presence_character_ids} =
|
||||
WandererApp.Cache.lookup("map_#{map_id}:presence_character_ids", [])
|
||||
|
||||
presence_character_ids
|
||||
|> Enum.map(fn character_id ->
|
||||
Task.start_link(fn ->
|
||||
character_updates =
|
||||
maybe_update_online(map_id, character_id) ++
|
||||
maybe_update_tracking_status(map_id, character_id) ++
|
||||
maybe_update_location(map_id, character_id) ++
|
||||
maybe_update_ship(map_id, character_id) ++
|
||||
maybe_update_alliance(map_id, character_id) ++
|
||||
maybe_update_corporation(map_id, character_id)
|
||||
presence_character_ids
|
||||
|> Task.async_stream(
|
||||
fn character_id ->
|
||||
character_updates =
|
||||
maybe_update_online(map_id, character_id) ++
|
||||
maybe_update_tracking_status(map_id, character_id) ++
|
||||
maybe_update_location(map_id, character_id) ++
|
||||
maybe_update_ship(map_id, character_id) ++
|
||||
maybe_update_alliance(map_id, character_id) ++
|
||||
maybe_update_corporation(map_id, character_id)
|
||||
|
||||
character_updates
|
||||
|> Enum.filter(fn update -> update != :skip end)
|
||||
|> Enum.map(fn update ->
|
||||
update
|
||||
|> case do
|
||||
{:character_location, location_info, old_location_info} ->
|
||||
update_location(
|
||||
character_id,
|
||||
location_info,
|
||||
old_location_info,
|
||||
state
|
||||
)
|
||||
character_updates
|
||||
|> Enum.filter(fn update -> update != :skip end)
|
||||
|> Enum.map(fn update ->
|
||||
update
|
||||
|> case do
|
||||
{:character_location, location_info, old_location_info} ->
|
||||
update_location(
|
||||
character_id,
|
||||
location_info,
|
||||
old_location_info,
|
||||
state
|
||||
)
|
||||
|
||||
:broadcast
|
||||
:broadcast
|
||||
|
||||
{:character_ship, _info} ->
|
||||
:broadcast
|
||||
{:character_ship, _info} ->
|
||||
:broadcast
|
||||
|
||||
{:character_online, _info} ->
|
||||
:broadcast
|
||||
{:character_online, _info} ->
|
||||
:broadcast
|
||||
|
||||
{:character_tracking, _info} ->
|
||||
:broadcast
|
||||
{:character_tracking, _info} ->
|
||||
:broadcast
|
||||
|
||||
{:character_alliance, _info} ->
|
||||
WandererApp.Cache.insert_or_update(
|
||||
"map_#{map_id}:invalidate_character_ids",
|
||||
[character_id],
|
||||
fn ids ->
|
||||
[character_id | ids]
|
||||
end
|
||||
)
|
||||
{:character_alliance, _info} ->
|
||||
WandererApp.Cache.insert_or_update(
|
||||
"map_#{map_id}:invalidate_character_ids",
|
||||
[character_id],
|
||||
fn ids ->
|
||||
[character_id | ids] |> Enum.uniq()
|
||||
end
|
||||
)
|
||||
|
||||
:broadcast
|
||||
:broadcast
|
||||
|
||||
{:character_corporation, _info} ->
|
||||
WandererApp.Cache.insert_or_update(
|
||||
"map_#{map_id}:invalidate_character_ids",
|
||||
[character_id],
|
||||
fn ids ->
|
||||
[character_id | ids]
|
||||
end
|
||||
)
|
||||
{:character_corporation, _info} ->
|
||||
WandererApp.Cache.insert_or_update(
|
||||
"map_#{map_id}:invalidate_character_ids",
|
||||
[character_id],
|
||||
fn ids ->
|
||||
[character_id | ids] |> Enum.uniq()
|
||||
end
|
||||
)
|
||||
|
||||
:broadcast
|
||||
:broadcast
|
||||
|
||||
_ ->
|
||||
:skip
|
||||
end
|
||||
end)
|
||||
|> Enum.filter(fn update -> update != :skip end)
|
||||
|> Enum.uniq()
|
||||
|> Enum.each(fn update ->
|
||||
case update do
|
||||
:broadcast ->
|
||||
update_character(map_id, character_id)
|
||||
_ ->
|
||||
:skip
|
||||
end
|
||||
end)
|
||||
|> Enum.filter(fn update -> update != :skip end)
|
||||
|> Enum.uniq()
|
||||
|> Enum.each(fn update ->
|
||||
case update do
|
||||
:broadcast ->
|
||||
update_character(map_id, character_id)
|
||||
|
||||
_ ->
|
||||
:ok
|
||||
end
|
||||
end)
|
||||
_ ->
|
||||
:ok
|
||||
end
|
||||
end)
|
||||
|
||||
:ok
|
||||
:ok
|
||||
end,
|
||||
timeout: :timer.seconds(15),
|
||||
max_concurrency: System.schedulers_online(),
|
||||
on_timeout: :kill_task
|
||||
)
|
||||
|> Enum.each(fn
|
||||
{:ok, _result} -> :ok
|
||||
{:error, reason} -> Logger.error("Error in update_characters: #{inspect(reason)}")
|
||||
end)
|
||||
end)
|
||||
rescue
|
||||
e ->
|
||||
Logger.error("""
|
||||
[Map Server] update_characters => exception: #{Exception.message(e)}
|
||||
#{Exception.format_stacktrace(__STACKTRACE__)}
|
||||
""")
|
||||
end
|
||||
end
|
||||
|
||||
defp update_character(map_id, character_id) do
|
||||
|
||||
@@ -32,7 +32,7 @@ defmodule WandererApp.Map.Server.Impl do
|
||||
@backup_state_timeout :timer.minutes(1)
|
||||
@update_presence_timeout :timer.seconds(5)
|
||||
@update_characters_timeout :timer.seconds(1)
|
||||
@update_tracked_characters_timeout :timer.seconds(1)
|
||||
@update_tracked_characters_timeout :timer.minutes(1)
|
||||
|
||||
def new(), do: __struct__()
|
||||
def new(args), do: __struct__(args)
|
||||
@@ -96,7 +96,13 @@ defmodule WandererApp.Map.Server.Impl do
|
||||
)
|
||||
|
||||
Process.send_after(self(), :update_characters, @update_characters_timeout)
|
||||
Process.send_after(self(), :update_tracked_characters, 100)
|
||||
|
||||
Process.send_after(
|
||||
self(),
|
||||
:update_tracked_characters,
|
||||
@update_tracked_characters_timeout
|
||||
)
|
||||
|
||||
Process.send_after(self(), :update_presence, @update_presence_timeout)
|
||||
Process.send_after(self(), :cleanup_connections, 5_000)
|
||||
Process.send_after(self(), :cleanup_systems, 10_000)
|
||||
|
||||
@@ -8,13 +8,13 @@ defmodule WandererApp.MapChainPassagesRepo do
|
||||
to
|
||||
)
|
||||
|> case do
|
||||
{:ok, connection} ->
|
||||
{:ok, %{inserted_at: inserted_at} = _connection} when not is_nil(inserted_at) ->
|
||||
{:ok, from_passages} =
|
||||
WandererApp.Api.MapChainPassages.by_connection(%{
|
||||
map_id: map_id,
|
||||
from: from,
|
||||
to: to,
|
||||
after: connection.inserted_at
|
||||
after: inserted_at
|
||||
})
|
||||
|
||||
{:ok, to_passages} =
|
||||
@@ -22,7 +22,7 @@ defmodule WandererApp.MapChainPassagesRepo do
|
||||
map_id: map_id,
|
||||
from: to,
|
||||
to: from,
|
||||
after: connection.inserted_at
|
||||
after: inserted_at
|
||||
})
|
||||
|
||||
from_passages =
|
||||
@@ -39,7 +39,7 @@ defmodule WandererApp.MapChainPassagesRepo do
|
||||
|
||||
{:ok, passages}
|
||||
|
||||
{:error, _error} ->
|
||||
_error ->
|
||||
{:ok, []}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,7 +11,7 @@ defmodule WandererAppWeb.PresenceGracePeriodManager do
|
||||
require Logger
|
||||
|
||||
# 30 minutes
|
||||
@grace_period_ms :timer.minutes(30)
|
||||
@grace_period_ms :timer.minutes(10)
|
||||
@check_remove_queue_interval :timer.seconds(30)
|
||||
|
||||
defstruct pending_removals: %{}, timers: %{}, to_remove: []
|
||||
|
||||
Reference in New Issue
Block a user