feat(config): add per-remote sync interval#836
Conversation
roborev: Combined Review (
|
roborev: Combined Review (
|
|
Addressed. |
roborev: Combined Review (
|
roborev: Combined Review (
|
roborev: Combined Review (
|
|
rebasing |
- fix(config): skip periodic remote sync when host validation fails - chore: retrigger CI after flaky e2e - feat(config): emit SSE event after scheduled remote sync - fix(config): add done channel to remote sync loop to prevent goroutine leaks in tests - fix(config): gate remote sync SSE emit on sessions actually synced
33e7f6e to
16e75a8
Compare
Remote host intervals configure daemon scheduling and should not become part of the manual remote sync authorization contract. Non-local daemon requests should continue to match configured hosts by the SSH target identity only, so clients do not need to echo scheduling-only config back to the server.\n\nScheduled remote sync also needs to emit the same sessions scope as manual remote sync so SSE consumers refresh consistently.
roborev: Combined Review (
|
The scheduled remote sync scope test only needs to capture the first emitted scope. Leaving later sends blocking can strand the sync loop inside the test emitter before it observes the done channel, which makes the test vulnerable to scheduler timing in CI.
roborev: Combined Review (
|
Scheduled remote sync writes to the same SQLite archive and remote skip cache as manual remote sync. Running it outside the daemon sync engine lock allowed interval jobs to overlap local sync or resync work, which could leave skip-cache state ahead of the archive after a DB swap.\n\nRun scheduled remote pulls under the engine exclusive lock so they share the same single-writer boundary as daemon-owned manual remote sync.
roborev: Combined Review (
|
Background daemons use the idle tracker to avoid shutting down while internal write work is active. The scheduled remote sync loop was outside that boundary, so an idle timeout could begin shutdown while SSH sync was still writing to SQLite under the exclusive sync lock.\n\nWrap each scheduled remote sync tick in idle-tracked work so active remote pulls postpone idle shutdown and new ticks are skipped once the daemon is draining.
roborev: Combined Review (
|
Scheduled remote sync uses the remote skip cache, so it cannot safely run incrementally while the local archive still needs a parser data-version resync. If the initial resync aborts and leaves NeedsResync true, unchanged remote files must be parsed again instead of skipped against stale cache state.\n\nUse the DB stale-data marker to force full scheduled remote pulls until the archive has been rebuilt successfully.
roborev: Combined Review (
|
Scheduled remote sync shells out through SSH helpers that honor command contexts, but the scheduled path was still passing context.Background. That let remote child processes outlive serve cancellation and daemon shutdown.\n\nThread the serve context through the scheduled sync loop and remote runner so ticker goroutines exit on cancellation and in-flight remote sync commands receive the same cancellation signal.
roborev: Combined Review (
|
|
good, merging. thank you! |
The serve daemon already runs a local sync every fifteen minutes, but the
[[remote_hosts]]entries introduced in #600 are only ever pulled by the one-shotagentsview synccommand, so a long-running daemon never refreshes data from configured remotes on its own. Users running the dashboard as a persistent service have to drive remote pulls out-of-band with cron or a wrapper script, which is exactly the kind of scheduling the daemon is otherwise responsible for.This adds an optional
intervalfield to each[[remote_hosts]]entry, expressed as a duration string such as"5m"or"1h". The field is decoded natively the same wayevents_coalesce_intervalis, and it defaults to zero, which means "do not periodically sync this host." Configs written before this change behave exactly as they do today, and nothing starts pulling from a remote unless the user explicitly sets an interval.On the daemon side, the periodic sync routine now launches one lightweight ticker goroutine per remote host that has a positive interval, each calling the same single-host sync path the CLI uses, in incremental mode, logging any failure without disturbing the others or the local periodic sync. After a successful remote sync pass, the goroutine emits a
data_changedSSE event through the serve broadcaster so connected UI clients pick up the new data immediately rather than waiting for the next local periodic sync. The emitter is threaded as async.Emitterinterface to keep the dependency direction clean; the CLI path continues to run without one. The remote host list is validated before these goroutines start; if validation fails the daemon logs a warning and keeps serving with local sync intact rather than refusing to start. The existing fifteen-minute local sync loop is left untouched, and because per-host remote sync reuses the already-testedrunRemoteSyncOncepath, the new surface area is the configuration field, its validation, the scheduling glue, and the emit-on-success behavior.Tests cover loading the new field from a config file, validating the negative-interval case, and the emit-on-success/no-emit-on-error/nil-emitter behavior of the sync loop.
Closes #412