Daemon is the local agent runtime that polls for and executes tasks.
| 151 | |
| 152 | // Daemon is the local agent runtime that polls for and executes tasks. |
| 153 | type Daemon struct { |
| 154 | cfg Config |
| 155 | client *Client |
| 156 | repoCache repoCacheBackend |
| 157 | skillCache *SkillBundleCache |
| 158 | logger *slog.Logger |
| 159 | |
| 160 | mu sync.Mutex |
| 161 | workspaces map[string]*workspaceState |
| 162 | runtimeIndex map[string]Runtime // runtimeID -> Runtime for provider lookups |
| 163 | // profileLaunchSpecs maps a custom runtime profile_id -> the absolute |
| 164 | // executable path plus fixed launch args resolved for that profile |
| 165 | // (MUL-3284). Populated in registerRuntimesForWorkspace when a profile's |
| 166 | // command resolves; read by runTask to launch the custom command for a |
| 167 | // claimed task. Guarded by mu. |
| 168 | profileLaunchSpecs map[string]profileLaunchSpec |
| 169 | reloading sync.Mutex // prevents concurrent workspace syncs |
| 170 | runtimeSet *runtimeSetWatcher // multi-subscriber pub/sub for runtime-set changes |
| 171 | |
| 172 | versionsMu sync.RWMutex // guards agentVersions |
| 173 | agentVersions map[string]string // provider -> detected CLI version (set during registration) |
| 174 | |
| 175 | wsHBMu sync.RWMutex // guards wsHBLastAck |
| 176 | wsHBLastAck map[string]time.Time // runtime_id -> last successful WS heartbeat ack timestamp |
| 177 | |
| 178 | // reconcile fans out a "re-check server state now" signal to subscribers |
| 179 | // (watchTaskCancellation, workspaceSyncLoop) so the WS connect/reconnect |
| 180 | // path can shrink the 5s / 30s reconciliation gap to sub-second. See |
| 181 | // reconcile.go and runTaskWakeupConnection. |
| 182 | reconcile *reconcileBroadcaster |
| 183 | |
| 184 | // runtimeGoneMu guards runtimeGoneInflight, reregisterNextAttempt, and |
| 185 | // reregisterLastCompletedAt. The state lets heartbeat / poller / WS-ack |
| 186 | // handlers converge on a single recovery path when they each detect that a |
| 187 | // runtime row was deleted server-side without three of them stampeding |
| 188 | // registerRuntimesForWorkspace. |
| 189 | runtimeGoneMu sync.Mutex |
| 190 | runtimeGoneInflight map[string]struct{} // runtime_id -> currently recovering |
| 191 | reregisterNextAttempt map[string]time.Time // workspace_id -> earliest time the next re-register attempt may run |
| 192 | reregisterLastCompletedAt map[string]time.Time // workspace_id -> wall-clock at which the last SUCCESSFUL re-register call returned (failures intentionally not stamped — see recordRegisterCompletion) |
| 193 | |
| 194 | cancelFunc context.CancelFunc // set by Run(); called by triggerRestart |
| 195 | rootCtx context.Context // set by Run(); used by long-running recoveries that must survive per-runtime ctx cancellation |
| 196 | restartBinary string // non-empty after a successful update; path to the new binary |
| 197 | updating atomic.Bool // prevents concurrent update attempts |
| 198 | activeTasks atomic.Int64 // number of tasks currently in handleTask; exposed via /health |
| 199 | ready atomic.Bool // false until preflight completes; gates /health status (starting -> running) |
| 200 | |
| 201 | // claimMu guards pauseClaims and claimsInFlight. It is held only for the |
| 202 | // microseconds it takes to make a decision; ClaimTask itself runs without |
| 203 | // the lock so a slow per-runtime claim cannot stall auto-update or any |
| 204 | // other poller. |
| 205 | // |
| 206 | // The pair is the auto-update path's barrier against the issue's |
| 207 | // requirement that "升级过程中如果有 task 进来,会延后升级而不是中断 task": |
| 208 | // runRuntimePoller refuses to call ClaimTask while pauseClaims is set, and |
| 209 | // tryAutoUpdate refuses to flip pauseClaims while any poller is mid-claim |
| 210 | // or any task is in handleTask. Together that closes the fetch-then-claim |
nothing calls this directly
no outgoing calls
no test coverage detected