feat(core): implement core/scheduler#466
Conversation
- Add `Scheduler` struct (WIP) - Add `new_slot_ticker`
- Fix duplicated code
- `valcache` is required by scheduler - Fixes cyclical dependency issue
- Use `valcache` to get the list of active validators.
- TODO's regarding concurrent access while resolving duties
- Try to reuse existing infrastructure
- Preserve only Actor API
- Fix edge case when trimming small epochs
- Not needed in practice, and they are large structs that would be expensive to clone.
|
@claude review |
|
Claude finished @emlautarom1's task in 4m 19s —— View job Review:
|
| pluto-ssz.workspace = true | ||
| ssz.workspace = true | ||
| tree_hash.workspace = true | ||
| anyhow.workspace = true |
There was a problem hiding this comment.
I think we can move it back to dev dependecies
| /// Subscribes a callback function for triggered slots. | ||
| pub fn subscribe_slot( | ||
| &mut self, | ||
| f: impl Fn(&types::Slot) -> Result<()> + Send + 'static, |
There was a problem hiding this comment.
Should we support async functions here as well?
There was a problem hiding this comment.
Changed to support async callbacks. There is a tradeoff here to make:
- If we await on each callback we can block the subscriber, meaning that it could lag behind the producer (current behavior), but ensures that callbacks are proceed in order with as single running task.
- If we run each callback on separate tasks we don't lag behind, but we have an unbounded number of running tasks and we cannot ensure ordering (ex. the callback for slot 1 could not complete before we start running the callback for 2)
Charon uses the second approach but I'm not sure it's the right one.
Note that if we just returned the Receiver channel to the caller then it would be a per-caller decision (more flexibility, we push the decision for later).
|
|
||
| // TODO: We might want to return a handle so clients can `.abort()` them to drop | ||
| // the subscription | ||
| tokio::spawn(async move { |
There was a problem hiding this comment.
I would pass cancellation token here / store the handles in the struct and then on join them on drop
There was a problem hiding this comment.
Not needed actually: when the actor gets dropped the rx.recv() call returns Err(Closed) so it exits automatically.
I'm thinking that maybe this approach of passing callbacks is not very good, and instead we should return the .subscribe() result received channel and let the caller decide what to do (ex. run it as tokio::spawn/tokio::spawn_blocking, handle cancellation, etc.)
Closes #176
Uses an Actor model to implement the
core/schedulermodule, solving some concurrency hacks that the original implementation had.Metrics have been ported using the existing Vise patterns but are untested.