pub struct ReactiveEngine<S, N: Network = Ethereum> { /* private fields */ }Expand description
Binds a ReactiveRuntime to an EventSubscriber for the common
subscribe-ingest lifecycle.
The engine treats the runtime registry as the single source of truth for
handler lifecycle: register_handler and
unregister_handler update runtime routing and
subscriber interests as one operation, keyed by the handler’s stable
HandlerId. Registration is continuity-safe by default — once the runtime
has journaled a canonical block, a newly registered handler is backfilled
from that block, so a pool discovered in block N (say via a factory
PoolCreated event) misses none of its own logs from N onward even though
its live subscription starts later. Overlap between backfill and live
delivery is absorbed by subscriber and runtime dedup.
Registration methods by intent:
| Method | Backfill |
|---|---|
register_handler | from the runtime’s last canonical block (live-only on a fresh runtime) |
register_handler_with_backfill | explicit range or anchor (deep history) |
register_handler_live_only | none — future logs only |
Unregistering a handler stops future subscription routing and runtime
decode for that handler; it deliberately does not evict EvmCache state
or undo runtime side effects. See
unregister_handler for the complete teardown
recipe.
The runtime and subscriber stay independently accessible through
runtime_mut / subscriber_mut
for advanced use. One caution: avoid calling
EventSubscriber::register_interests (the full-replacement setup API) on
an engine-managed subscriber — implementations may clear owner-scoped
bookkeeping, after which per-handler unregistration no longer releases the
handler’s transport subscriptions. To bootstrap the subscriber from a
runtime that already has handlers, use
sync_handler_interests, which registers
one owner per handler instead of one unowned blob.
Implementations§
Source§impl<S, N> ReactiveEngine<S, N>where
N: Network,
S: EventSubscriber<N>,
impl<S, N> ReactiveEngine<S, N>where
N: Network,
S: EventSubscriber<N>,
Sourcepub fn new(runtime: ReactiveRuntime<N>, subscriber: S) -> Self
pub fn new(runtime: ReactiveRuntime<N>, subscriber: S) -> Self
Bind a runtime and subscriber.
Sourcepub fn into_parts(self) -> (ReactiveRuntime<N>, S)
pub fn into_parts(self) -> (ReactiveRuntime<N>, S)
Split the engine into its runtime and subscriber parts.
Sourcepub fn runtime(&self) -> &ReactiveRuntime<N>
pub fn runtime(&self) -> &ReactiveRuntime<N>
Borrow the runtime.
Sourcepub fn runtime_mut(&mut self) -> &mut ReactiveRuntime<N>
pub fn runtime_mut(&mut self) -> &mut ReactiveRuntime<N>
Mutably borrow the runtime.
Sourcepub fn subscriber(&self) -> &S
pub fn subscriber(&self) -> &S
Borrow the subscriber.
Sourcepub fn subscriber_mut(&mut self) -> &mut S
pub fn subscriber_mut(&mut self) -> &mut S
Mutably borrow the subscriber.
Sourcepub fn next_batch(&mut self) -> SubscriberNextBatch<'_, N>
pub fn next_batch(&mut self) -> SubscriberNextBatch<'_, N>
Poll the subscriber for the next batch.
Sourcepub fn ingest_batch(
&mut self,
cache: &mut EvmCache,
batch: ReactiveInputBatch<N>,
) -> Result<ReactiveBatchReport<N>, ReactiveError>
pub fn ingest_batch( &mut self, cache: &mut EvmCache, batch: ReactiveInputBatch<N>, ) -> Result<ReactiveBatchReport<N>, ReactiveError>
Ingest one already-polled batch through the runtime (direct effects only; surfaced resync requests are reported, not executed).
Sourcepub fn ingest_batch_with_resync(
&mut self,
cache: &mut EvmCache,
batch: ReactiveInputBatch<N>,
) -> Result<ReactiveBatchReport<N>, ReactiveError>
pub fn ingest_batch_with_resync( &mut self, cache: &mut EvmCache, batch: ReactiveInputBatch<N>, ) -> Result<ReactiveBatchReport<N>, ReactiveError>
Ingest one already-polled batch and execute the storage/account resyncs
it surfaces, exactly like
ReactiveRuntime::ingest_batch_with_resync.
Sourcepub async fn next_ingest(
&mut self,
cache: &mut EvmCache,
) -> Result<Option<ReactiveBatchReport<N>>, ReactiveEngineError>
pub async fn next_ingest( &mut self, cache: &mut EvmCache, ) -> Result<Option<ReactiveBatchReport<N>>, ReactiveEngineError>
Poll the subscriber once and ingest the returned batch when present (direct effects only).
Sourcepub async fn next_ingest_with_resync(
&mut self,
cache: &mut EvmCache,
) -> Result<Option<ReactiveBatchReport<N>>, ReactiveEngineError>
pub async fn next_ingest_with_resync( &mut self, cache: &mut EvmCache, ) -> Result<Option<ReactiveBatchReport<N>>, ReactiveEngineError>
Poll the subscriber once and ingest the returned batch with resync execution — the loop shape for consumers that rely on coverage-gap repair (root-gate resyncs, handler-requested re-reads).
Source§impl<S, N> ReactiveEngine<S, N>where
N: Network,
S: InterestOwnerSubscriber<N>,
impl<S, N> ReactiveEngine<S, N>where
N: Network,
S: InterestOwnerSubscriber<N>,
Sourcepub fn register_handler(
&mut self,
handler: Arc<dyn ReactiveHandler<N>>,
) -> Result<(), ReactiveEngineRegisterError>
pub fn register_handler( &mut self, handler: Arc<dyn ReactiveHandler<N>>, ) -> Result<(), ReactiveEngineRegisterError>
Register a handler with both the runtime and subscriber, backfilling its log interests from the runtime’s last canonical block.
This is the continuity-safe default for mid-lifecycle registration: the
runtime already knows how far it has processed the chain, so the new
handler’s logs are fetched from that block forward and no discovery gap
opens between “we decided to track this pool” and “its live subscription
started”. On a runtime that has not journaled any canonical block yet
(fresh start, or journal_depth 0) registration is live-only, matching
pre-ingestion bootstrap. Use
register_handler_with_backfill
for deeper history or
register_handler_live_only to opt
out of backfill entirely.
If subscriber registration fails, the runtime registration is rolled back before the error is returned.
Sourcepub fn register_handler_with_backfill(
&mut self,
handler: Arc<dyn ReactiveHandler<N>>,
backfill: SubscriberBackfill,
) -> Result<(), ReactiveEngineRegisterError>
pub fn register_handler_with_backfill( &mut self, handler: Arc<dyn ReactiveHandler<N>>, backfill: SubscriberBackfill, ) -> Result<(), ReactiveEngineRegisterError>
Register a handler and request an explicit owner-scoped log backfill for its interests (deep history / custom anchors).
If subscriber registration fails, the runtime registration is rolled back before the error is returned.
Sourcepub fn register_handler_live_only(
&mut self,
handler: Arc<dyn ReactiveHandler<N>>,
) -> Result<(), ReactiveEngineRegisterError>
pub fn register_handler_live_only( &mut self, handler: Arc<dyn ReactiveHandler<N>>, ) -> Result<(), ReactiveEngineRegisterError>
Register a handler without any log backfill — only logs delivered after its live subscription starts are routed to it.
If subscriber registration fails, the runtime registration is rolled back before the error is returned.
Sourcepub fn sync_handler_interests(&mut self) -> Result<(), SubscriberError>
pub fn sync_handler_interests(&mut self) -> Result<(), SubscriberError>
Register every handler currently in the runtime registry as a subscriber interest owner.
This is the bootstrap path for an engine built around a pre-populated
runtime: each handler becomes its own owner (upsert semantics, so
rerunning is safe and already-registered owners are refreshed in place).
No backfill is requested — bootstrap happens before ingestion starts, so
there is no processed position to be continuous with; use
register_handler_with_backfill
for handlers that need history. Owners are not removed by this call: use
unregister_handler for lifecycle removal
rather than mutating the runtime registry directly.
On error, owners already synced stay registered (upserts are independent); the call can simply be retried.
Sourcepub fn unregister_handler(
&mut self,
id: &HandlerId,
) -> Option<Arc<dyn ReactiveHandler<N>>>
pub fn unregister_handler( &mut self, id: &HandlerId, ) -> Option<Arc<dyn ReactiveHandler<N>>>
Unregister a handler from both the subscriber and runtime.
Subscriber interests are removed first so no new live records are routed to a handler after it has left the runtime registry. Returns the removed handler when the id was registered.
This is the routing/transport half of dropping an adapter. State the handler accumulated is deliberately left in place; the complete teardown for a pool or adapter that will not return is:
engine.unregister_handler(&id);
for address in handler_addresses {
// stop root-gate eth_getProof probes for the account
engine.runtime_mut().untrack_account(address);
// drop its queued (unexecuted) repair work from the pending ledger
engine.runtime_mut().cancel_pending_resyncs(address);
}
// optional: evict cached state via StateUpdate::purge / cache purge APIsHealth, metrics, the reorg journal, hooks, and freshness stamps are runtime-global and are never touched by handler removal.
Auto Trait Implementations§
impl<S, N = Ethereum> !Freeze for ReactiveEngine<S, N>
impl<S, N = Ethereum> !RefUnwindSafe for ReactiveEngine<S, N>
impl<S, N = Ethereum> !UnwindSafe for ReactiveEngine<S, N>
impl<S, N> Send for ReactiveEngine<S, N>where
S: Send,
impl<S, N> Sync for ReactiveEngine<S, N>where
S: Sync,
impl<S, N> Unpin for ReactiveEngine<S, N>
impl<S, N> UnsafeUnpin for ReactiveEngine<S, N>where
S: UnsafeUnpin,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.