View Source ProcessHub.Strategy.Migration.SwapMigration (ProcessHub v0.6.0)
Shared migration logic used by both ColdSwap and HotSwap strategies.
This module extracts the common patterns for topology expansion and contraction so that both strategies can reuse the same core logic while differing only in their termination timing and post-action behavior.
Summary
Functions
Nodes each child_id belongs to, per the hub's current distribution.
Generic state collection with configurable response message atom.
Computes processable children for migration during topology expansion.
Dispatches Hook.migration_completed() if migrated list is non-empty.
Groups [{cspec, meta, target_nodes}] into %{node => [{cspec, meta}]}.
Full contraction logic (identical for both strategies).
Full topology expansion for both swap strategies: consent gate, then migration.
Handles delivery of pre-sent shutdown states when processes start on the target node.
Handles graceful shutdown by querying states from all local processes and sending them to target nodes before this node goes down.
Stores received shutdown state data on the target node.
Migrates forward_to ([{cspec, meta, target_nodes}]), handing over state and
terminating the stop_local children per the strategy's swap semantics.
Shared post-action logic on target node.
Splits the processable set by migration consent: participating local children
are queried under a shared consent_timeout deadline, and :defer/no-reply
children as well as already-deferred ones are removed from the set. Returns
{processable, newly_deferred_child_ids}; no-op without consent settings.
Queries consent from each {child_id, pid} pair and returns the child ids
that replied :ready within the shared timeout deadline.
Sends start requests via Dispatcher if non-empty.
Functions
@spec belongs_to(ProcessHub.Hub.t(), [ProcessHub.child_id()]) :: %{ required(ProcessHub.child_id()) => [node()] }
Nodes each child_id belongs to, per the hub's current distribution.
@spec collect_states([ProcessHub.child_id()], non_neg_integer(), list(), atom()) :: list()
Generic state collection with configurable response message atom.
ColdSwap uses :coldswap_state, HotSwap uses :hotswap_state.
@spec compute_processable(ProcessHub.Hub.t(), map()) :: {map(), map(), map()}
Computes processable children for migration during topology expansion.
Gets migration candidates, calculates distribution, populates handler.calculated_cids,
and categorizes children into %{stop_local: [...], forward_to: [...]}.
Returns {handler, processable, migration_candidates}.
@spec dispatch_migration_hook(ProcessHub.Hub.t(), [ProcessHub.child_spec()], [node()]) :: :ok
Dispatches Hook.migration_completed() if migrated list is non-empty.
@spec group_children_by_node([{ProcessHub.child_spec(), map(), [node()]}]) :: %{ required(node()) => [{ProcessHub.child_spec(), map()}] }
Groups [{cspec, meta, target_nodes}] into %{node => [{cspec, meta}]}.
@spec handle_contraction(ProcessHub.Hub.t(), map()) :: map()
Full contraction logic (identical for both strategies).
Uses pre-calculated handler.calculated_cids to start children locally
that should now be PRIMARY on the local node.
@spec handle_expansion(ProcessHub.Hub.t(), struct(), [node()], map()) :: map()
Full topology expansion for both swap strategies: consent gate, then migration.
@spec handle_process_startups(ProcessHub.Hub.t(), list(), atom(), atom()) :: nil
Handles delivery of pre-sent shutdown states when processes start on the target node.
Parameters:
hub- the hub structcpids- list of%{cid: child_id, pid: pid}structs from process_startups hookstorage_key- ETS key where shutdown states are storeddelivery_msg- atom for delivery message (e.g.:coldswap_handover)
handle_shutdown(hub, timeout, query_msg, response_msg, callback_mod, log_prefix)
View Source@spec handle_shutdown( ProcessHub.Hub.t(), non_neg_integer(), atom(), atom(), module(), String.t() ) :: :ok
Handles graceful shutdown by querying states from all local processes and sending them to target nodes before this node goes down.
Parameters:
hub- the hub structtimeout- state query timeout in msquery_msg- atom to send to processes (e.g.:query_cold_handover_state)response_msg- atom expected in response (e.g.:coldswap_state)callback_mod- module containinghandle_storage_update/2for remote castlog_prefix- string for timeout log messages (e.g."ColdSwap")
@spec handle_storage_update(ProcessHub.Hub.t(), list(), atom()) :: :ok
Stores received shutdown state data on the target node.
Called via GenServer.cast from the shutting-down node.
@spec migrate(ProcessHub.Hub.t(), struct(), list(), [ProcessHub.child_id()]) :: :ok
Migrates forward_to ([{cspec, meta, target_nodes}]), handing over state and
terminating the stop_local children per the strategy's swap semantics.
notify_originating_node(hub, results, originating_node, child_ids, callback_mod, callback_fun)
View Source@spec notify_originating_node( ProcessHub.Hub.t(), [ProcessHub.Request.Handler.StartChildrenRequest.PostStartData.t()], node(), [ProcessHub.child_id()], module(), atom() ) :: :ok
Shared post-action logic on target node.
Filters successfully started children, sends callback to originating node.
@spec partition_by_consent(ProcessHub.Hub.t(), struct(), map(), map()) :: {map(), [ProcessHub.child_id()]}
Splits the processable set by migration consent: participating local children
are queried under a shared consent_timeout deadline, and :defer/no-reply
children as well as already-deferred ones are removed from the set. Returns
{processable, newly_deferred_child_ids}; no-op without consent settings.
@spec query_consent([{ProcessHub.child_id(), pid()}], non_neg_integer()) :: MapSet.t()
Queries consent from each {child_id, pid} pair and returns the child ids
that replied :ready within the shared timeout deadline.
@spec send_start_requests(ProcessHub.Hub.t(), [ ProcessHub.Request.Handler.StartChildrenRequest.t() ]) :: :ok
Sends start requests via Dispatcher if non-empty.