fix(daemon): auto-discover new workspaces without restart
The daemon now periodically fetches the user's workspace list from the API (every 30s) and adds any new workspaces to the watched config. The existing config-watch loop then picks up the change and registers runtimes. This fixes the issue where workspaces created after `multica login` were not discovered until the daemon was restarted.
This commit is contained in:
parent
457a3eb555
commit
25ed043117
3 changed files with 75 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,60 @@ 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) {
|
||||
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