feat(agent): event-driven uplink — sync on every state transition
The agent reported its state only on the adaptive sync tick (3s watching / 10s idle), so a resolving→downloading→verifying→organizing→completed transition could lag up to a full interval before the server (and the web UI) saw it. Now every successful Task.Transition fires an onChange hook wired to TriggerSync, pushing the new state immediately. Bursts are safe: TriggerSync is a buffered-1 send, so clustered transitions coalesce into one sync. - Task gains an onChange hook fired AFTER the status mutex is released (so a future heavier hook can't deadlock on task.mu); nil is a no-op. - Manager.OnStateChange is set on each task at Submit; the daemon wires it to TriggerSync alongside the existing OnTaskDone. - Stream tasks transition outside the Manager, so handleStreamTask wires the same hook explicitly (gap found in review) — resolving/downloading/ completed/failed on the stream path now push too. The adaptive ticker stays as a reconciliation heartbeat; it's just no longer the latency floor for state changes.
This commit is contained in:
parent
1052529ca2
commit
864b6ea832
5 changed files with 83 additions and 4 deletions
|
|
@ -34,6 +34,13 @@ type Manager struct {
|
|||
// Used by the daemon to trigger an immediate sync.
|
||||
OnTaskDone func()
|
||||
|
||||
// OnStateChange is called after EVERY successful task status transition
|
||||
// (resolving → downloading → verifying → organizing → seeding → done/failed),
|
||||
// wired by the daemon to trigger an immediate sync so the server sees state
|
||||
// changes in near-realtime instead of on the next adaptive tick. Coalesced
|
||||
// downstream (TriggerSync is a buffered-1 send), so bursts collapse safely.
|
||||
OnStateChange func()
|
||||
|
||||
// recentlyFinished holds tasks that completed/failed since the last sync read.
|
||||
// The sync goroutine reads and clears this to include final states in the next sync.
|
||||
recentMu sync.Mutex
|
||||
|
|
@ -82,6 +89,8 @@ func NewManager(cfg ManagerConfig, reporter *ProgressReporter, downloaders ...Do
|
|||
// Submit queues a task for download. Non-blocking if capacity available.
|
||||
func (m *Manager) Submit(ctx context.Context, at agent.Task) {
|
||||
task := NewTaskFromAgent(at)
|
||||
// Event-driven uplink: push every status transition to the server immediately.
|
||||
task.SetOnChange(m.OnStateChange)
|
||||
|
||||
// Per-task cancellable context so CancelTask can unblock the goroutine
|
||||
taskCtx, taskCancel := context.WithCancel(ctx)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue