From 3c10c7f5f437f4c9379e2375bd9997a5c36868e7 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Wed, 9 Nov 2022 11:01:34 -0600 Subject: [PATCH] fix: Subscribe to template updates on the workspace page (#4979) Fixes #4969. --- coderd/templateversions.go | 17 +++++++++++++++++ coderd/workspaces.go | 22 +++++++++++++++++++--- coderd/workspaces_test.go | 6 ++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/coderd/templateversions.go b/coderd/templateversions.go index 1d3ccb7919..330f0c39b6 100644 --- a/coderd/templateversions.go +++ b/coderd/templateversions.go @@ -1,6 +1,7 @@ package coderd import ( + "context" "database/sql" "encoding/json" "errors" @@ -12,6 +13,8 @@ import ( "github.com/moby/moby/pkg/namesgenerator" "golang.org/x/xerrors" + "cdr.dev/slog" + "github.com/coder/coder/coderd/audit" "github.com/coder/coder/coderd/database" "github.com/coder/coder/coderd/httpapi" @@ -660,6 +663,8 @@ func (api *API) patchActiveTemplateVersion(rw http.ResponseWriter, r *http.Reque newTemplate.ActiveVersionID = req.ID aReq.New = newTemplate + api.publishTemplateUpdate(ctx, template.ID) + httpapi.Write(ctx, rw, http.StatusOK, codersdk.Response{ Message: "Updated the active template version!", }) @@ -946,3 +951,15 @@ func convertTemplateVersion(version database.TemplateVersion, job codersdk.Provi CreatedBy: createdBy, } } + +func watchTemplateChannel(id uuid.UUID) string { + return fmt.Sprintf("template:%s", id) +} + +func (api *API) publishTemplateUpdate(ctx context.Context, templateID uuid.UUID) { + err := api.Pubsub.Publish(watchTemplateChannel(templateID), []byte{}) + if err != nil { + api.Logger.Warn(ctx, "failed to publish template update", + slog.F("template_id", templateID), slog.Error(err)) + } +} diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 5a293a5a68..38d5310736 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -886,7 +886,7 @@ func (api *API) watchWorkspace(rw http.ResponseWriter, r *http.Request) { // Ignore all trace spans after this, they're not too useful. ctx = trace.ContextWithSpan(ctx, tracing.NoopSpan) - cancelSubscribe, err := api.Pubsub.Subscribe(watchWorkspaceChannel(workspace.ID), func(_ context.Context, _ []byte) { + sendUpdate := func(_ context.Context, _ []byte) { workspace, err := api.Database.GetWorkspaceByID(ctx, workspace.ID) if err != nil { _ = sendEvent(ctx, codersdk.ServerSentEvent{ @@ -920,7 +920,9 @@ func (api *API) watchWorkspace(rw http.ResponseWriter, r *http.Request) { findUser(workspace.OwnerID, data.users), ), }) - }) + } + + cancelWorkspaceSubscribe, err := api.Pubsub.Subscribe(watchWorkspaceChannel(workspace.ID), sendUpdate) if err != nil { _ = sendEvent(ctx, codersdk.ServerSentEvent{ Type: codersdk.ServerSentEventTypeError, @@ -931,7 +933,21 @@ func (api *API) watchWorkspace(rw http.ResponseWriter, r *http.Request) { }) return } - defer cancelSubscribe() + defer cancelWorkspaceSubscribe() + + // This is required to show whether the workspace is up-to-date. + cancelTemplateSubscribe, err := api.Pubsub.Subscribe(watchTemplateChannel(workspace.TemplateID), sendUpdate) + if err != nil { + _ = sendEvent(ctx, codersdk.ServerSentEvent{ + Type: codersdk.ServerSentEventTypeError, + Data: codersdk.Response{ + Message: "Internal error subscribing to template events.", + Detail: err.Error(), + }, + }) + return + } + defer cancelTemplateSubscribe() // An initial ping signals to the request that the server is now ready // and the client can begin servicing a channel with data. diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index 0fbc9b973e..ca92537da0 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -1430,6 +1430,12 @@ func TestWorkspaceWatcher(t *testing.T) { require.NoError(t, err) wait() + err = client.UpdateActiveTemplateVersion(ctx, template.ID, codersdk.UpdateActiveTemplateVersion{ + ID: template.ActiveVersionID, + }) + require.NoError(t, err) + wait() + cancel() }