Skip to content

Commit 7d29502

Browse files
authored
Handle context cancellation in proxy logs (#3378)
1 parent 546f5cb commit 7d29502

File tree

1 file changed

+24
-6
lines changed

1 file changed

+24
-6
lines changed

cmd/thv/app/logs.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import (
88
"errors"
99
"fmt"
1010
"os"
11+
"os/signal"
1112
"path/filepath"
1213
"strings"
14+
"syscall"
1315
"time"
1416

1517
"github.com/adrg/xdg"
@@ -94,14 +96,20 @@ func logsCmdFunc(cmd *cobra.Command, args []string) error {
9496
follow := viper.GetBool("follow")
9597
proxy := viper.GetBool("proxy")
9698

99+
if follow {
100+
var cancel context.CancelFunc
101+
ctx, cancel = signal.NotifyContext(ctx, syscall.SIGINT, syscall.SIGTERM)
102+
defer cancel()
103+
}
104+
97105
manager, err := workloads.NewManager(ctx)
98106
if err != nil {
99107
return fmt.Errorf("failed to create workload manager: %w", err)
100108
}
101109

102110
if proxy {
103111
if follow {
104-
return getProxyLogs(workloadName)
112+
return getProxyLogs(ctx, workloadName)
105113
}
106114
// Use the shared manager method for non-follow proxy logs
107115
// CLI gets all logs (0 = unlimited)
@@ -246,7 +254,7 @@ func reportPruneResults(prunedFiles, errs []string) {
246254
}
247255

248256
// getProxyLogs reads and displays the proxy logs for a given workload in follow mode
249-
func getProxyLogs(workloadName string) error {
257+
func getProxyLogs(ctx context.Context, workloadName string) error {
250258
// Get the proxy log file path
251259
logFilePath, err := xdg.DataFile(fmt.Sprintf("toolhive/logs/%s.log", workloadName))
252260
if err != nil {
@@ -262,11 +270,11 @@ func getProxyLogs(workloadName string) error {
262270
return nil
263271
}
264272

265-
return followProxyLogFile(cleanLogFilePath)
273+
return followProxyLogFile(ctx, cleanLogFilePath)
266274
}
267275

268276
// followProxyLogFile implements tail -f functionality for proxy logs
269-
func followProxyLogFile(logFilePath string) error {
277+
func followProxyLogFile(ctx context.Context, logFilePath string) error {
270278
// Clean the file path to prevent path traversal
271279
cleanLogFilePath := filepath.Clean(logFilePath)
272280

@@ -295,6 +303,11 @@ func followProxyLogFile(logFilePath string) error {
295303
}
296304

297305
// Follow the file for new content
306+
contentCheckInterval := 100 * time.Millisecond
307+
308+
ticker := time.NewTicker(contentCheckInterval)
309+
defer ticker.Stop()
310+
298311
for {
299312
// Read any new content
300313
buffer := make([]byte, 1024)
@@ -307,7 +320,12 @@ func followProxyLogFile(logFilePath string) error {
307320
fmt.Print(string(buffer[:n]))
308321
}
309322

310-
// Sleep briefly before checking for more content
311-
time.Sleep(100 * time.Millisecond)
323+
// Wait for next iteration or cancellation
324+
select {
325+
case <-ctx.Done():
326+
return nil
327+
case <-ticker.C:
328+
// Continue to next iteration
329+
}
312330
}
313331
}

0 commit comments

Comments
 (0)