@@ -570,11 +570,27 @@ func (api *API) workspaceAgentLogs(rw http.ResponseWriter, r *http.Request) {
570
570
lastSentLogID = logs [len (logs )- 1 ].ID
571
571
}
572
572
573
+ workspaceNotifyCh := make (chan struct {}, 1 )
573
574
notifyCh := make (chan struct {}, 1 )
574
575
// Allow us to immediately check if we missed any logs
575
576
// between initial fetch and subscribe.
576
577
notifyCh <- struct {}{}
577
578
579
+ // Subscribe to workspace to detect new builds.
580
+ closeSubscribeWorkspace , err := api .Pubsub .Subscribe (codersdk .WorkspaceNotifyChannel (workspace .ID ), func (_ context.Context , _ []byte ) {
581
+ select {
582
+ case workspaceNotifyCh <- struct {}{}:
583
+ default :
584
+ }
585
+ })
586
+ if err != nil {
587
+ httpapi .Write (ctx , rw , http .StatusInternalServerError , codersdk.Response {
588
+ Message : "Failed to subscribe to workspace for log streaming." ,
589
+ Detail : err .Error (),
590
+ })
591
+ return
592
+ }
593
+ defer closeSubscribeWorkspace ()
578
594
// Subscribe early to prevent missing log events.
579
595
closeSubscribe , err := api .Pubsub .Subscribe (agentsdk .LogsNotifyChannel (workspaceAgent .ID ), func (_ context.Context , _ []byte ) {
580
596
// The message is not important, we're tracking lastSentLogID manually.
@@ -585,7 +601,7 @@ func (api *API) workspaceAgentLogs(rw http.ResponseWriter, r *http.Request) {
585
601
})
586
602
if err != nil {
587
603
httpapi .Write (ctx , rw , http .StatusInternalServerError , codersdk.Response {
588
- Message : "Failed to subscribe to logs ." ,
604
+ Message : "Failed to subscribe to agent for log streaming ." ,
589
605
Detail : err .Error (),
590
606
})
591
607
return
@@ -600,20 +616,33 @@ func (api *API) workspaceAgentLogs(rw http.ResponseWriter, r *http.Request) {
600
616
defer t .Stop ()
601
617
602
618
go func () {
603
- defer close (bufferedLogs )
619
+ defer func () {
620
+ logger .Debug (ctx , "end log streaming loop" )
621
+ close (bufferedLogs )
622
+ }()
623
+ logger .Debug (ctx , "start log streaming loop" , slog .F ("last_sent_log_id" , lastSentLogID ))
604
624
605
625
keepGoing := true
606
626
for keepGoing {
627
+ var (
628
+ debugTriggeredBy string
629
+ onlyCheckLatestBuild bool
630
+ )
607
631
select {
608
632
case <- ctx .Done ():
609
633
return
610
634
case <- t .C :
635
+ debugTriggeredBy = "timer"
636
+ case <- workspaceNotifyCh :
637
+ debugTriggeredBy = "workspace"
638
+ onlyCheckLatestBuild = true
611
639
case <- notifyCh :
640
+ debugTriggeredBy = "log"
612
641
t .Reset (recheckInterval )
613
642
}
614
643
615
644
agents , err := api .Database .GetWorkspaceAgentsInLatestBuildByWorkspaceID (ctx , workspace .ID )
616
- if err != nil {
645
+ if err != nil && ! xerrors . Is ( err , sql . ErrNoRows ) {
617
646
if xerrors .Is (err , context .Canceled ) {
618
647
return
619
648
}
@@ -624,6 +653,20 @@ func (api *API) workspaceAgentLogs(rw http.ResponseWriter, r *http.Request) {
624
653
// checking once.
625
654
keepGoing = slices .ContainsFunc (agents , func (agent database.WorkspaceAgent ) bool { return agent .ID == workspaceAgent .ID })
626
655
656
+ logger .Debug (
657
+ ctx ,
658
+ "checking for new logs" ,
659
+ slog .F ("triggered_by" , debugTriggeredBy ),
660
+ slog .F ("only_check_latest_build" , onlyCheckLatestBuild ),
661
+ slog .F ("keep_going" , keepGoing ),
662
+ slog .F ("last_sent_log_id" , lastSentLogID ),
663
+ slog .F ("workspace_has_agents" , len (agents ) > 0 ),
664
+ )
665
+
666
+ if onlyCheckLatestBuild && keepGoing {
667
+ continue
668
+ }
669
+
627
670
logs , err := api .Database .GetWorkspaceAgentLogsAfter (ctx , database.GetWorkspaceAgentLogsAfterParams {
628
671
AgentID : workspaceAgent .ID ,
629
672
CreatedAfter : lastSentLogID ,
0 commit comments