The challenge responder and replica-sync coordinator (and for now the checkpoint coordinator) share the same run-loop scaffolding: a start() that spawns the loop and hands back a command handle, a biased tokio::select! over command/event/interval arms, pause/stop command handling, the events_open disarm for a closed broadcast channel, Lagged → bootstrap-rescan recovery, and the safety-net interval. Only the duty-specific behavior differs.
Raised by @bkontur in #291 (comment): extract the shared scaffolding into a common trait Coordinator/actor abstraction that owns the tokio/channel/restart handling (including what happens when a coordinator task dies or panics), with per-impl hooks for the relevance filter, event reaction, bootstrap scan, and tick action — without pulling in an actor framework.
Sequencing: this should land after #311 (which removes the checkpoint coordinator, shrinking the surface to two loops) and after #297 (stacked on #291), so the refactor doesn't churn under both.
Relates to #291.
The challenge responder and replica-sync coordinator (and for now the checkpoint coordinator) share the same run-loop scaffolding: a
start()that spawns the loop and hands back a command handle, a biasedtokio::select!over command/event/interval arms, pause/stop command handling, theevents_opendisarm for a closed broadcast channel,Lagged→ bootstrap-rescan recovery, and the safety-net interval. Only the duty-specific behavior differs.Raised by @bkontur in #291 (comment): extract the shared scaffolding into a common
trait Coordinator/actor abstraction that owns the tokio/channel/restart handling (including what happens when a coordinator task dies or panics), with per-impl hooks for the relevance filter, event reaction, bootstrap scan, and tick action — without pulling in an actor framework.Sequencing: this should land after #311 (which removes the checkpoint coordinator, shrinking the surface to two loops) and after #297 (stacked on #291), so the refactor doesn't churn under both.
Relates to #291.