View Source ProcessHub.Service.Migration (ProcessHub v0.8.0)
Deferred-migration list and graceful node drain for the migration consent
protocol. See ProcessHub.Strategy.Migration.MigrationConsent.
Summary
Functions
Parks children in the deferred list and ensures the retry tick runs.
Drains the local node before shutdown: removes it from the distribution
cluster-wide, migrates every local child away through the consent gate, and
force-migrates whatever is still deferred at the :timeout deadline
(default 60000 ms). Leaves children untouched on error.
One retry pass: prunes entries whose child died or is assigned back to the local node, migrates the ready, re-consenting and expired ones, and returns the number of entries left.
Migrates one child to target_node, handing its state over per the hub's
migration strategy — the same per-child move a drain performs, invocable for
a single child with an explicit target. The child's declared-list entry is
untouched by the move, so a crash mid-migration heals through the reconcile
instead of losing the child.
Marks a deferred child ready; it migrates on the next retry tick.
Types
@type entry() :: %{ child_id: ProcessHub.child_id(), deferred_at: integer(), ready: boolean() }
Functions
@spec defer_children(ProcessHub.Hub.t(), [ProcessHub.child_id()]) :: :ok
Parks children in the deferred list and ensures the retry tick runs.
@spec deferred_child_ids(ProcessHub.Hub.t()) :: MapSet.t()
@spec deferred_list(ProcessHub.Hub.t()) :: [entry()]
@spec drain( ProcessHub.hub_id() | ProcessHub.Hub.t(), keyword() ) :: {:ok, %{migrated: non_neg_integer(), forced: non_neg_integer()}} | {:error, :no_target_nodes | :draining | :partitioned | :locked}
Drains the local node before shutdown: removes it from the distribution
cluster-wide, migrates every local child away through the consent gate, and
force-migrates whatever is still deferred at the :timeout deadline
(default 60000 ms). Leaves children untouched on error.
A drain pass still queued at the deadline is waited for and whatever it
defers is forced, so the drain then overruns :timeout by the work queued
ahead of the pass, the pass's consent wait (at most :consent_timeout) and
the forced moves.
Returns once every other node has confirmed it dropped this node. A node confirms behind the children it moved here before, during its own drain or redistribution, so those have been passed on by then. A node silent at the deadline is logged as a warning, and one whose hub or node goes away is not waited for.
A hub with work still queued, such as a membership change or a start, answers
{:error, :locked} by default. Pass when_busy: :wait to drain it anyway:
the drain's pass runs on the worker queue behind that work.
@spec draining?(ProcessHub.Hub.t()) :: boolean()
@spec handle_retry_tick(ProcessHub.Hub.t()) :: non_neg_integer()
One retry pass: prunes entries whose child died or is assigned back to the local node, migrates the ready, re-consenting and expired ones, and returns the number of entries left.
@spec migrate_child(ProcessHub.hub_id(), ProcessHub.child_id(), node()) :: :ok | {:error, :not_found | :not_a_member | :same_node | term()}
Migrates one child to target_node, handing its state over per the hub's
migration strategy — the same per-child move a drain performs, invocable for
a single child with an explicit target. The child's declared-list entry is
untouched by the move, so a crash mid-migration heals through the reconcile
instead of losing the child.
Runs on the node currently hosting the child and routes itself there when called elsewhere. The consent protocol is NOT queried — the caller decides the child may move; a drain remains the consent-gated path.
The distribution strategy still considers the child assigned by its own arithmetic, so a later topology event may migrate it back — callers healing toward an off-assignment placement must be prepared to re-apply.
@spec migration_ready(ProcessHub.hub_id() | ProcessHub.Hub.t(), ProcessHub.child_id()) :: :ok | {:error, :not_deferred}
Marks a deferred child ready; it migrates on the next retry tick.
@spec retry_interval(ProcessHub.Hub.t()) :: pos_integer()