Supervision dispatch module#
The supervision dispatch module provides peer discovery, cooperative
lifecycle management, failure detection, and fenced action dispatch across
localities, built on top of the supervision
module’s lifecycle events and admission checks. See that module’s reference
for the semantics of hpx::supervision::check_admission and
hpx::supervision::dispatch_outcome; this page documents only the
dispatch-specific surface layered on top of them. For the narrative on
initialization ordering, one-shot discovery, shadow-state semantics, and
client-side filtering versus fenced-dispatch admission, see
Supervision dispatch.
Overview#
Functions#
Function |
Description |
|---|---|
Types#
Type |
Description |
|---|---|
Lifecycle initialization and shutdown#
-
hpx::shared_future<hpx::supervision::registry> hpx::supervision::init(hpx::chrono::steady_duration const &discovery_timeout = hpx::supervision::default_discovery_timeout)
-
hpx::supervision::registry hpx::supervision::init(hpx::launch::sync_policy, hpx::chrono::steady_duration const &discovery_timeout = hpx::supervision::default_discovery_timeout)
Performs one-shot, idempotent initialization of the supervision-dispatch runtime for this locality: creates a local registry, publishes
event::startedbefore its symbol name is registered, registers that name, and performs a single discover_and_join() pass. Calling init() while already active is a no-op; concurrent callers duringinitializingattach to the in-flight operation instead of racing it.
-
void hpx::supervision::finalize()
Performs one-shot, idempotent teardown of the runtime previously started by init(): publishes
event::completedat the current/unchanged epoch, unregisters the registry’s symbol name, and releases the registry. A no-op unless the runtime is currentlyactive. It returns promptly even while a failure detection sweep is still waiting on unresponsive peers, andhpx::disconnect()orhpx::stop()may follow right away: the sweep’s outstanding waits are resolved at the latest during runtime shutdown and do no further work once the supervision runtime has been finalized.
-
bool hpx::supervision::is_initialized() noexcept
Returns whether the runtime is currently
active. Never blocks; safe to call from any thread, including while init()/finalize() is in flight.
Peer discovery#
-
constexpr std::chrono::milliseconds hpx::supervision::default_discovery_timeout#
Default timeout (60 seconds) used by init(), discover_peers(), fan_out_join(), and discover_and_join().
-
constexpr std::uint64_t hpx::supervision::unjoined_epoch#
Sentinel (
std::numeric_limits<std::uint64_t>::max()) stored indiscovered_peer::join_epochfor a peer that has not been joined yet.0cannot serve this purpose because it is a legitimate join epoch.
-
struct hpx::supervision::discovered_peer#
A peer whose registry symbol name resolved during a discover_peers() call. Holds
locality,registry_client, andjoin_epoch. discover_peers() leavesjoin_epochathpx::supervision::unjoined_epoch(never0, which is a legitimate join epoch); fan_out_join() fills it in with the epoch recorded byregistry::join().localityis cached for convenience but is never independently resolved or validated: it is always derived fromregistry_clientitself (seeregistry::get_locality()), since exactly one registry exists per locality.
-
std::vector<hpx::supervision::discovered_peer> hpx::supervision::discover_peers(hpx::chrono::steady_duration const &timeout = hpx::supervision::default_discovery_timeout)#
Performs a one-time discovery pull: concurrently resolves the pinned registry name of every remote locality, bounded by a single wait for
timeout. Localities that have not yet called init() are silently excluded rather than causing a hang or failure.
-
std::vector<hpx::supervision::discovered_peer> hpx::supervision::fan_out_join(hpx::supervision::registry const &local_registry, std::vector<hpx::supervision::discovered_peer> const &peers, hpx::chrono::steady_duration const &timeout = hpx::supervision::default_discovery_timeout)#
Fans out
join()calls fromlocal_registryto every entry inpeers. Reusesregistry::join()’s reservation/idempotency machinery, so repeated or overlapping calls never create more than one shadow per peer locality.Returns a
discovered_peerfor each peer whosejoin()call settled successfully withintimeout, in the same relative order aspeers, withjoin_epochfilled in. Peers whosejoin()call did not settle in time, or settled with an exception, are omitted from the result (rather than left as gaps or defaulted entries), so the returned vector is a same-order subset ofpeers, not index-aligned with it. A join that timed out is retracted viaregistry::leave()if it later succeeds; a join that failed has nothing to retract. Either way,snapshot_peers()never reports a peer this call dropped.
-
std::vector<hpx::supervision::discovered_peer> hpx::supervision::discover_and_join(hpx::supervision::registry const &local_registry, hpx::chrono::steady_duration const &timeout = hpx::supervision::default_discovery_timeout)#
Composes a single discovery-and-join pass: one discover_peers() pull followed by one fan_out_join() call, then a short poll of
local_registry.snapshot_peers()until every joined peer is visible there.timeoutis a single budget shared by all three steps. Introduces no background thread, timer, or repeated broadcast.Returns the
discovered_peervector produced by fan_out_join(). If the visibility poll runs out of time, the peers that did join are still returned, even thoughsnapshot_peers()may not list them yet.
State query and event publication#
-
std::uint64_t hpx::supervision::current_epoch(hpx::launch::sync_policy, hpx::id_type const &locality, hpx::error_code &ec = hpx::throws)#
Returns the dispatch-cycle epoch of the supervision-dispatch runtime on
locality: the counter init() increments once per initialization sequence (before registration and discovery, so a sequence that later fails still advances it) and publishesevent::startedunder.0if no initialization sequence has run onlocality. This is unrelated to any target’slifecycle_state::epoch;registry::join()uses it to seed a new peer’s shadow from the peer’s real epoch.
-
hpx::future<hpx::supervision::lifecycle_state> hpx::supervision::query_state(hpx::supervision::registry const &handle)#
-
hpx::supervision::lifecycle_state hpx::supervision::query_state(hpx::launch::sync_policy, hpx::supervision::registry const &handle, hpx::error_code &ec = hpx::throws)#
-
hpx::future<hpx::supervision::lifecycle_state> hpx::supervision::query_state(hpx::supervision::registry const &handle, hpx::supervision::discovered_peer const &peer)#
-
hpx::supervision::lifecycle_state hpx::supervision::query_state(hpx::launch::sync_policy, hpx::supervision::registry const &handle, hpx::supervision::discovered_peer const &peer, hpx::error_code &ec = hpx::throws)#
The self variants resolve both locality and target to
hpx::find_here()and query it on the local locality; the peer variants resolve both locality and target frompeer.localityinstead -handleis accepted only for overload resolution and symmetry with the self variants, and is otherwise unused in that case. Each overload is a thin forwarder over the corresponding raw-id query_state() overload in Supervision module; see that module’s reference for the fields of the returnedlifecycle_state, including theepochvalue useful for recovering the epoch a handle’s locality was started at.
-
hpx::future<hpx::supervision::publish_result> hpx::supervision::publish_event(hpx::supervision::registry const &handle, hpx::supervision::event ev, std::uint64_t epoch = 0)#
-
hpx::supervision::publish_result hpx::supervision::publish_event(hpx::launch::sync_policy, hpx::supervision::registry const &handle, hpx::supervision::event ev, std::uint64_t epoch = 0, hpx::error_code &ec = hpx::throws)#
Handle-based convenience overloads of hpx::supervision::publish_event that resolve both locality and target to
hpx::find_here()instead of requiring the caller to name them explicitly. Thin forwarders over the raw-id publish_event() overloads in Supervision module. There is no peer variant: a locality publishes lifecycle events only for itself, never on behalf of a peer. The default epoch value of 0 is only correct for a locality’s very first publication after init(); once the target’s real epoch has advanced, 0 is stale. Callers publishing events after the initial one should first obtain the current epoch - e.g. viaquery_state(hpx::launch::sync, handle).epoch- and pass it explicitly.
Registry client#
-
class hpx::supervision::registry
A lightweight, self-supervising client handle for pairing with peer localities; mirrors a peer’s lifecycle state locally via
join()and can itself be discovered by name in AGAS.-
registry() = default#
Constructs an empty client that is not connected to any component. Does not create a server-side component.
-
explicit registry(hpx::id_type const &target_locality)#
Creates a new registry component on
target_locality.
-
explicit registry(std::string const &symbolic_name)#
Connects to an existing registry component registered under
symbolic_name(seeregister_name()).
-
hpx::future<hpx::supervision::joined_peer> join(hpx::id_type const &peer_locality) const#
-
hpx::supervision::joined_peer join(hpx::launch::sync_policy, hpx::id_type const &peer_locality, hpx::error_code &ec = hpx::throws) const#
Joins a peer locality: creates (or reuses) local supervision state mirroring the peer’s lifecycle. The returned
joined_peer::targetispeer_localityitself (not a generated local id) and is what dispatch_work() colocates against. Joining a peer that is already fully joined returns the existingjoined_peerwithout seeding or registering observers again.
-
void leave(hpx::id_type const &peer_locality, hpx::future<hpx::supervision::joined_peer> &&f) const#
Attaches a fire-and-forget continuation to a pending
join()future that retracts the join once it settles. Used by fan_out_join() for joins that did not complete within its timeout. Exceptions from the underlyingjoin()are swallowed.
-
hpx::future<std::vector<hpx::supervision::server::peer_snapshot>> snapshot_peers() const#
-
std::vector<hpx::supervision::server::peer_snapshot> snapshot_peers(hpx::launch::sync_policy, hpx::error_code &ec = hpx::throws) const#
Returns a point-in-time snapshot of all fully joined, non-evicting peers.
-
registry() = default#
-
struct hpx::supervision::joined_peer
Returned by
registry::join(). Holdstarget, the peer’s locality (the value passed tojoin()), andjoin_epoch, the epoch the peer was joined at.join_epochis used byregistry::leave()to tell a join apart from a later re-join of the same locality. Note thatjoined_peer::join_epochdefaults to0, whilediscovered_peer::join_epochdefaults tounjoined_epoch.
-
struct hpx::supervision::server::peer_snapshot
Plain-data view of a single joined peer:
peer_localityandjoin_epoch.
Fenced dispatch#
-
template<typename Action, typename ...Ts>
decltype(auto) hpx::supervision::dispatch_work(hpx::id_type const &target, std::uint64_t epoch, Ts&&... ts)# Dispatches
Actiontotargetunder supervision fencing. Performs a cheap, non-authoritative admission check on the caller’s locality to short-circuit an already-known-fenced target, then dispatches to the target’s own locality (viahpx::colocated) where an authoritative re-check against the same latch consulted by hpx::supervision::check_admission runs immediately before the wrapped action executes, on the same thread, closing the admission/invocation race. See Supervision dispatch for the full client-side-filtering versus fenced-admission narrative and worked examples.- Returns:
A future holding the result of the dispatched action. If either admission check rejects the call, the future becomes exceptional with
hpx::error::target_fenced(surfacing atget()), and the wrapped action is not invoked. dispatch_work() itself does not throw for a fenced target.
-
template<typename Action, typename ...Ts>
decltype(auto) hpx::supervision::dispatch_work(Action, hpx::id_type const &target, std::uint64_t epoch, Ts&&... ts)# Same as above, with the action passed as an instance instead of a template argument. Constrained to
hpx::traits::is_action_v<Action>.
-
template<typename Action, typename ...Ts>
decltype(auto) hpx::supervision::dispatch_work(Action, hpx::supervision::discovered_peer const &peer, Ts&&... ts)# Dispatches against a peer returned by fan_out_join() or discover_and_join(); forwards to
dispatch_work<Action>(peer.locality, peer.join_epoch, ts...). A peer whosejoin_epochis stillunjoined_epoch(e.g. one returned by discover_peers() alone) is rejected up front with the sametarget_fencedexceptional future.
-
template<std::meta::info F, typename ...Ts>
decltype(auto) hpx::supervision::dispatch_work(hpx::id_type const &target, std::uint64_t epoch, Ts&&... ts)#
-
template<std::meta::info F, typename ...Ts>
decltype(auto) hpx::supervision::dispatch_work(hpx::supervision::discovered_peer const &peer, Ts&&... ts)# Reflection-based overloads, available only when
HPX_HAVE_CXX26_REFLECTIONis defined.Fis a reflection of a namespace-scope free function (^^fn); these forward to the corresponding overloads above withhpx::actions::reflect_action<F>as the action.
-
template<typename Action, typename IdType, typename Epoch, typename ...Ts>
decltype(auto) hpx::supervision::invoke_fenced_action(Action act, IdType target, Epoch const epoch, Ts... ts) The body that runs on the target’s locality once dispatch_work() has dispatched. Performs the authoritative check_admission() re-check and, if admitted, invokes
actvia hpx::sync withtargetandts...(epochis not forwarded).- Throws:
hpx::exception with
hpx::error::target_fencedif the target has latched a terminal event forepoch;actis not invoked in that case. The caller of dispatch_work() sees this as the exceptional state of the returned future.
-
template<typename Action, typename IdType, typename Epoch, typename ...Ts>
struct hpx::supervision::fenced_action# HPX action wrapper for
invoke_fenced_action<Action, IdType, Epoch, Ts...>, dispatched bydispatch_work()viahpx::colocated.
-
template<typename Action>
struct hpx::supervision::make_fenced_action# Type trait yielding the
fenced_actionspecialization forAction, withIdTypefixed to hpx::id_type,Epochtostd::uint64_t, and the remaining arguments taken fromAction::arguments_type. Constrained tohpx::traits::is_action_v<Action>.make_fenced_action_t<Action>is shorthand formake_fenced_action<Action>::type.
Testing support#
The following are declared in hpx/supervision_dispatch/testing.hpp and are
not part of the stable public dispatch API; they exist solely to make
unit tests for this module deterministic:
-
std::vector<hpx::supervision::server::peer_snapshot> hpx::supervision::testing::local_snapshot_peers()
-
void hpx::supervision::testing::set_failure_detection_poll_timeout_for_testing(hpx::chrono::steady_duration const &timeout)
-
hpx::id_type hpx::supervision::testing::last_join_locality()
-
void hpx::supervision::testing::suspend_heartbeat_for_testing()
-
bool hpx::supervision::testing::failure_detection_sweep_in_flight_for_testing()
-
void hpx::supervision::testing::stop_background_loops()
See the API reference of this module for more details, and Supervision module for the underlying lifecycle event, admission, and dispatch-outcome semantics this module builds on.