diff --git a/lib/wanderer_app/map/map_manager.ex b/lib/wanderer_app/map/map_manager.ex index a6b22890..f98ee25c 100644 --- a/lib/wanderer_app/map/map_manager.ex +++ b/lib/wanderer_app/map/map_manager.ex @@ -9,8 +9,8 @@ defmodule WandererApp.Map.Manager do alias WandererApp.Map.Server - @maps_start_per_second 10 - @maps_start_interval 1000 + @maps_start_chunk_size 20 + @maps_start_interval 500 @maps_queue :maps_queue @check_maps_queue_interval :timer.seconds(1) @@ -58,9 +58,9 @@ defmodule WandererApp.Map.Manager do {:ok, pings_cleanup_timer} = :timer.send_interval(@pings_cleanup_interval, :cleanup_pings) - safe_async_task(fn -> - start_last_active_maps() - end) + # safe_async_task(fn -> + # start_last_active_maps() + # end) {:ok, %{ @@ -153,7 +153,7 @@ defmodule WandererApp.Map.Manager do @maps_queue |> WandererApp.Queue.to_list!() |> Enum.uniq() - |> Enum.chunk_every(@maps_start_per_second) + |> Enum.chunk_every(@maps_start_chunk_size) WandererApp.Queue.clear(@maps_queue) diff --git a/lib/wanderer_app/map/map_pool.ex b/lib/wanderer_app/map/map_pool.ex index dc0c135a..07dfe880 100644 --- a/lib/wanderer_app/map/map_pool.ex +++ b/lib/wanderer_app/map/map_pool.ex @@ -15,6 +15,7 @@ defmodule WandererApp.Map.MapPool do @cache :map_pool_cache @registry :map_pool_registry @unique_registry :unique_map_pool_registry + @map_pool_limit 20 @garbage_collection_interval :timer.hours(4) @systems_cleanup_timeout :timer.minutes(30) @@ -94,34 +95,33 @@ defmodule WandererApp.Map.MapPool do def handle_cast(:stop, state), do: {:stop, :normal, state} @impl true - def handle_cast({:start_map, map_id}, state) do - case do_start_map(map_id, state) do - {:ok, new_state} -> - {:noreply, new_state} + def handle_call({:start_map, map_id}, _from, %{map_ids: map_ids, uuid: uuid} = state) do + # Enforce capacity limit to prevent pool overload due to race conditions + if length(map_ids) >= @map_pool_limit do + Logger.warning( + "[Map Pool #{uuid}] Pool at capacity (#{length(map_ids)}/#{@map_pool_limit}), " <> + "rejecting map #{map_id} and triggering new pool creation" + ) - {:error, _reason} -> - # Error already logged in do_start_map - {:noreply, state} + # Trigger a new pool creation attempt asynchronously + # This allows the system to create a new pool for this map + spawn(fn -> + WandererApp.Map.MapPoolDynamicSupervisor.start_map(map_id) + end) + + {:reply, :ok, state} + else + case do_start_map(map_id, state) do + {:ok, new_state} -> + {:reply, :ok, new_state} + + {:error, _reason} -> + # Error already logged in do_start_map + {:reply, :ok, state} + end end end - @impl true - def handle_cast( - {:stop_map, map_id}, - %{map_ids: map_ids, uuid: uuid} = state - ) do - Registry.update_value(@unique_registry, Module.concat(__MODULE__, uuid), fn r_map_ids -> - r_map_ids |> Enum.reject(fn id -> id == map_id end) - end) - - Cachex.del(@cache, map_id) - - map_id - |> Server.Impl.stop_map() - - {:noreply, %{state | map_ids: map_ids |> Enum.reject(fn id -> id == map_id end)}} - end - @impl true def handle_call( {:stop_map, map_id}, diff --git a/lib/wanderer_app/map/map_pool_dynamic_supervisor.ex b/lib/wanderer_app/map/map_pool_dynamic_supervisor.ex index 93deed26..232fb025 100644 --- a/lib/wanderer_app/map/map_pool_dynamic_supervisor.ex +++ b/lib/wanderer_app/map/map_pool_dynamic_supervisor.ex @@ -7,7 +7,7 @@ defmodule WandererApp.Map.MapPoolDynamicSupervisor do @cache :map_pool_cache @registry :map_pool_registry @unique_registry :unique_map_pool_registry - @map_pool_limit 10 + @map_pool_limit 20 @name __MODULE__ @@ -30,7 +30,7 @@ defmodule WandererApp.Map.MapPoolDynamicSupervisor do start_child([map_id], pools |> Enum.count()) pid -> - GenServer.cast(pid, {:start_map, map_id}) + GenServer.call(pid, {:start_map, map_id}) end end end @@ -59,7 +59,7 @@ defmodule WandererApp.Map.MapPoolDynamicSupervisor do find_pool_by_scanning_registry(map_id) [{pool_pid, _}] -> - GenServer.cast(pool_pid, {:stop_map, map_id}) + GenServer.call(pool_pid, {:stop_map, map_id}) end {:error, reason} -> @@ -102,7 +102,7 @@ defmodule WandererApp.Map.MapPoolDynamicSupervisor do # Update the cache to fix the inconsistency Cachex.put(@cache, map_id, pool_uuid) - GenServer.cast(pool_pid, {:stop_map, map_id}) + GenServer.call(pool_pid, {:stop_map, map_id}) nil -> Logger.debug("Map #{map_id} not found in any pool registry")