Merge pull request #194 from multica-ai/fix/daemon-auto-discover-new-workspaces
fix(daemon): auto-discover new workspaces without restart
This commit is contained in:
commit
9c3ff52363
3 changed files with 78 additions and 2 deletions
|
|
@ -146,6 +146,21 @@ func (c *Client) ReportPingResult(ctx context.Context, runtimeID, pingID string,
|
|||
return c.postJSON(ctx, fmt.Sprintf("/api/daemon/runtimes/%s/ping/%s/result", runtimeID, pingID), result, nil)
|
||||
}
|
||||
|
||||
// WorkspaceInfo holds minimal workspace metadata returned by the API.
|
||||
type WorkspaceInfo struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// ListWorkspaces fetches all workspaces the authenticated user belongs to.
|
||||
func (c *Client) ListWorkspaces(ctx context.Context) ([]WorkspaceInfo, error) {
|
||||
var workspaces []WorkspaceInfo
|
||||
if err := c.getJSON(ctx, "/api/workspaces", &workspaces); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return workspaces, nil
|
||||
}
|
||||
|
||||
func (c *Client) Deregister(ctx context.Context, runtimeIDs []string) error {
|
||||
return c.postJSON(ctx, "/api/daemon/deregister", map[string]any{
|
||||
"runtime_ids": runtimeIDs,
|
||||
|
|
|
|||
|
|
@ -16,8 +16,9 @@ const (
|
|||
DefaultHeartbeatInterval = 15 * time.Second
|
||||
DefaultAgentTimeout = 2 * time.Hour
|
||||
DefaultRuntimeName = "Local Agent"
|
||||
DefaultConfigReloadInterval = 5 * time.Second
|
||||
DefaultHealthPort = 19514
|
||||
DefaultConfigReloadInterval = 5 * time.Second
|
||||
DefaultWorkspaceSyncInterval = 30 * time.Second
|
||||
DefaultHealthPort = 19514
|
||||
DefaultMaxConcurrentTasks = 20
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -85,6 +85,9 @@ func (d *Daemon) Run(ctx context.Context) error {
|
|||
// Start config watcher for hot-reload.
|
||||
go d.configWatchLoop(ctx)
|
||||
|
||||
// Start workspace sync loop to discover newly created workspaces.
|
||||
go d.workspaceSyncLoop(ctx)
|
||||
|
||||
go d.heartbeatLoop(ctx)
|
||||
go d.usageScanLoop(ctx)
|
||||
go d.serveHealth(ctx, healthLn, time.Now())
|
||||
|
|
@ -276,6 +279,63 @@ func (d *Daemon) configWatchLoop(ctx context.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
// workspaceSyncLoop periodically fetches the user's workspaces from the API
|
||||
// and adds any new ones to the CLI config. The configWatchLoop will then
|
||||
// detect the config change and register runtimes for the new workspaces.
|
||||
func (d *Daemon) workspaceSyncLoop(ctx context.Context) {
|
||||
// Run immediately on startup before entering the periodic loop.
|
||||
d.syncWorkspacesFromAPI(ctx)
|
||||
|
||||
ticker := time.NewTicker(DefaultWorkspaceSyncInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
d.syncWorkspacesFromAPI(ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// syncWorkspacesFromAPI fetches all workspaces the user belongs to and adds
|
||||
// any missing ones to the CLI config's watched list.
|
||||
func (d *Daemon) syncWorkspacesFromAPI(ctx context.Context) {
|
||||
apiCtx, cancel := context.WithTimeout(ctx, 15*time.Second)
|
||||
defer cancel()
|
||||
|
||||
workspaces, err := d.client.ListWorkspaces(apiCtx)
|
||||
if err != nil {
|
||||
d.logger.Debug("workspace sync: failed to list workspaces", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
cfg, err := cli.LoadCLIConfig()
|
||||
if err != nil {
|
||||
d.logger.Warn("workspace sync: failed to load config", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
var added int
|
||||
for _, ws := range workspaces {
|
||||
if cfg.AddWatchedWorkspace(ws.ID, ws.Name) {
|
||||
added++
|
||||
d.logger.Info("workspace sync: discovered new workspace", "workspace_id", ws.ID, "name", ws.Name)
|
||||
}
|
||||
}
|
||||
|
||||
if added == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if err := cli.SaveCLIConfig(cfg); err != nil {
|
||||
d.logger.Warn("workspace sync: failed to save config", "error", err)
|
||||
return
|
||||
}
|
||||
d.logger.Info("workspace sync: added new workspace(s) to config", "count", added)
|
||||
}
|
||||
|
||||
// reloadWorkspaces reconciles the active workspace set with the config file.
|
||||
// NOTE: Token changes (e.g. re-login as a different user) are not picked up;
|
||||
// the daemon must be restarted for a new auth token to take effect.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue