@@ -2006,10 +2006,12 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro
20062006}
20072007}
20082008
2009- var taskAppID uuid.NullUUID
2010- var taskAgentID uuid.NullUUID
2011- var hasAITask bool
2012- var warnUnknownTaskAppID bool
2009+ var (
2010+ hasAITask bool
2011+ unknownAppID string
2012+ taskAppID uuid.NullUUID
2013+ taskAgentID uuid.NullUUID
2014+ )
20132015if tasks := jobType .WorkspaceBuild .GetAiTasks ();len (tasks )> 0 {
20142016hasAITask = true
20152017task := tasks [0 ]
@@ -2026,59 +2028,28 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro
20262028}
20272029
20282030if ! slices .Contains (appIDs ,appID ) {
2029- warnUnknownTaskAppID = true
2030- }
2031-
2032- id ,err := uuid .Parse (appID )
2033- if err != nil {
2034- return xerrors .Errorf ("parse app id: %w" ,err )
2035- }
2036-
2037- taskAppID = uuid.NullUUID {UUID :id ,Valid :true }
2038-
2039- agentID ,ok := agentIDByAppID [appID ]
2040- taskAgentID = uuid.NullUUID {UUID :agentID ,Valid :ok }
2041- }
2042-
2043- // This is a hacky workaround for the issue with tasks 'disappearing' on stop:
2044- // reuse has_ai_task and sidebar_app_id from the previous build.
2045- // This workaround should be removed as soon as possible.
2046- if workspaceBuild .Transition == database .WorkspaceTransitionStop && workspaceBuild .BuildNumber > 1 {
2047- if prevBuild ,err := s .Database .GetWorkspaceBuildByWorkspaceIDAndBuildNumber (ctx , database.GetWorkspaceBuildByWorkspaceIDAndBuildNumberParams {
2048- WorkspaceID :workspaceBuild .WorkspaceID ,
2049- BuildNumber :workspaceBuild .BuildNumber - 1 ,
2050- });err == nil {
2051- hasAITask = prevBuild .HasAITask .Bool
2052- taskAppID = prevBuild .AITaskSidebarAppID
2053- warnUnknownTaskAppID = false
2054- s .Logger .Debug (ctx ,"task workaround: reused has_ai_task and app_id from previous build to keep track of task" ,
2055- slog .F ("job_id" ,job .ID .String ()),
2056- slog .F ("build_number" ,prevBuild .BuildNumber ),
2057- slog .F ("workspace_id" ,workspace .ID ),
2058- slog .F ("workspace_build_id" ,workspaceBuild .ID ),
2059- slog .F ("transition" ,string (workspaceBuild .Transition )),
2060- slog .F ("sidebar_app_id" ,taskAppID .UUID ),
2061- slog .F ("has_ai_task" ,hasAITask ),
2062- )
2031+ unknownAppID = appID
20632032}else {
2064- s .Logger .Error (ctx ,"task workaround: tracking via has_ai_task and app_id from previous build failed" ,
2065- slog .Error (err ),
2066- slog .F ("job_id" ,job .ID .String ()),
2067- slog .F ("workspace_id" ,workspace .ID ),
2068- slog .F ("workspace_build_id" ,workspaceBuild .ID ),
2069- slog .F ("transition" ,string (workspaceBuild .Transition )),
2070- )
2033+ // Only parse for valid app and agent to avoid fk violation.
2034+ id ,err := uuid .Parse (appID )
2035+ if err != nil {
2036+ return xerrors .Errorf ("parse app id: %w" ,err )
2037+ }
2038+ taskAppID = uuid.NullUUID {UUID :id ,Valid :true }
2039+
2040+ agentID ,ok := agentIDByAppID [appID ]
2041+ taskAgentID = uuid.NullUUID {UUID :agentID ,Valid :ok }
20712042}
20722043}
20732044
2074- if warnUnknownTaskAppID {
2045+ if unknownAppID != "" && workspaceBuild . Transition == database . WorkspaceTransitionStart {
20752046// Ref: https://github.com/coder/coder/issues/18776
20762047// This can happen for a number of reasons:
20772048// 1. Misconfigured template
20782049// 2. Count=0 on the agent due to stop transition, meaning the associated coder_app was not inserted.
20792050// Failing the build at this point is not ideal, so log a warning instead.
20802051s .Logger .Warn (ctx ,"unknown ai_task_app_id" ,
2081- slog .F ("ai_task_app_id" ,taskAppID . UUID . String () ),
2052+ slog .F ("ai_task_app_id" ,unknownAppID ),
20822053slog .F ("job_id" ,job .ID .String ()),
20832054slog .F ("workspace_id" ,workspace .ID ),
20842055slog .F ("workspace_build_id" ,workspaceBuild .ID ),
@@ -2105,9 +2076,6 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro
21052076slog .F ("transition" ,string (workspaceBuild .Transition )),
21062077)
21072078}
2108- // Important: reset hasAITask and sidebarAppID so that we don't run into a fk constraint violation.
2109- hasAITask = false
2110- taskAppID = uuid.NullUUID {}
21112079}
21122080
21132081if hasAITask && workspaceBuild .Transition == database .WorkspaceTransitionStart {
@@ -2124,14 +2092,6 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro
21242092}
21252093}
21262094
2127- hasExternalAgent := false
2128- for _ ,resource := range jobType .WorkspaceBuild .Resources {
2129- if resource .Type == "coder_external_agent" {
2130- hasExternalAgent = true
2131- break
2132- }
2133- }
2134-
21352095if task ,err := db .GetTaskByWorkspaceID (ctx ,workspace .ID );err == nil {
21362096// Irrespective of whether the agent or sidebar app is present,
21372097// perform the upsert to ensure a link between the task and
@@ -2153,20 +2113,21 @@ func (s *server) completeWorkspaceBuildJob(ctx context.Context, job database.Pro
21532113return xerrors .Errorf ("get task by workspace id: %w" ,err )
21542114}
21552115
2156- // Regardless of whether there is an AI task or not, update the field to indicate one way or the other since it
2157- // always defaults to nil. ONLY if has_ai_task=true MUST ai_task_sidebar_app_id be set.
2116+ _ ,hasExternalAgent := slice .Find (jobType .WorkspaceBuild .Resources ,func (resource * sdkproto.Resource )bool {
2117+ return resource .Type == "coder_external_agent"
2118+ })
21582119if err := db .UpdateWorkspaceBuildFlagsByID (ctx , database.UpdateWorkspaceBuildFlagsByIDParams {
21592120ID :workspaceBuild .ID ,
21602121HasAITask : sql.NullBool {
21612122Bool :hasAITask ,
21622123Valid :true ,
21632124},
2125+ SidebarAppID :taskAppID ,// SidebarAppID is not required, but kept for API backwards compatibility.
21642126HasExternalAgent : sql.NullBool {
21652127Bool :hasExternalAgent ,
21662128Valid :true ,
21672129},
2168- SidebarAppID :taskAppID ,
2169- UpdatedAt :now ,
2130+ UpdatedAt :now ,
21702131});err != nil {
21712132return xerrors .Errorf ("update workspace build ai tasks and external agent flag: %w" ,err )
21722133}