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.

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

Link to this function

belongs_to(hub, child_ids)

View Source
@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.

Link to this function

collect_states(remaining_cids, timeout, acc, response_msg_atom)

View Source
@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.

Link to this function

compute_processable(hub, handler)

View Source
@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}.

Link to this function

dispatch_migration_hook(hub, migrated_cspecs, nodes)

View Source
@spec dispatch_migration_hook(ProcessHub.Hub.t(), [ProcessHub.child_spec()], [node()]) ::
  :ok

Dispatches Hook.migration_completed() if migrated list is non-empty.

Link to this function

group_children_by_node(forward_to_list)

View Source
@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}]}.

Link to this function

handle_contraction(hub, handler)

View Source
@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.

Link to this function

handle_expansion(hub, strategy, nodes, handler)

View Source
@spec handle_expansion(ProcessHub.Hub.t(), struct(), [node()], map()) :: map()

Full topology expansion for both swap strategies: consent gate, then migration.

Link to this function

handle_process_startups(hub, cpids, storage_key, delivery_msg)

View Source
@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 struct
  • cpids - list of %{cid: child_id, pid: pid} structs from process_startups hook
  • storage_key - ETS key where shutdown states are stored
  • delivery_msg - atom for delivery message (e.g. :coldswap_handover)
Link to this function

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 struct
  • timeout - state query timeout in ms
  • query_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 containing handle_storage_update/2 for remote cast
  • log_prefix - string for timeout log messages (e.g. "ColdSwap")
Link to this function

handle_storage_update(hub, data, storage_key)

View Source
@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.

Link to this function

migrate(hub, strategy, forward_to, stop_local)

View Source
@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.

Link to this function

notify_originating_node(hub, results, originating_node, child_ids, callback_mod, callback_fun)

View Source

Shared post-action logic on target node.

Filters successfully started children, sends callback to originating node.

Link to this function

partition_by_consent(hub, arg2, processable, candidates)

View Source
@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.

Link to this function

query_consent(cid_pids, timeout)

View Source
@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.

Link to this function

send_start_requests(hub, requests)

View Source
@spec send_start_requests(ProcessHub.Hub.t(), [
  ProcessHub.Request.Handler.StartChildrenRequest.t()
]) ::
  :ok

Sends start requests via Dispatcher if non-empty.