diff --git a/internal/backend/backend.go b/internal/backend/backend.go index da63876..7a7d6bb 100644 --- a/internal/backend/backend.go +++ b/internal/backend/backend.go @@ -82,10 +82,10 @@ func (c *Client) IngestEvent(ctx context.Context, req *agentv1.ProcessHookEventR return fmt.Errorf("send hook event: %w", err) } if err := stream.CloseRequest(); err != nil { - return err + return fmt.Errorf("close request: %w", err) } - if resp, err := stream.Receive(); err == nil { - _ = resp + if _, err := stream.Receive(); err != nil { + return fmt.Errorf("receive response: %w", err) } return stream.CloseResponse() } diff --git a/internal/run/run.go b/internal/run/run.go index ea9fc24..8cac58d 100644 --- a/internal/run/run.go +++ b/internal/run/run.go @@ -94,7 +94,10 @@ func Start(ctx context.Context, opts Options) error { } // 5. Start sidecar - sessionDir := filepath.Join(os.TempDir(), "kontext", sessionID) + // Use /tmp (not $TMPDIR) with a short ID to keep the Unix socket path + // under macOS's 104-byte sun_path limit. $TMPDIR on macOS is a long + // path like /var/folders/.../T/ which pushes the socket path over. + sessionDir := filepath.Join("/tmp", "kontext", truncateID(sessionID)) os.MkdirAll(sessionDir, 0700) sc, err := sidecar.New(sessionDir, client, sessionID, opts.Agent) @@ -126,8 +129,11 @@ func Start(ctx context.Context, opts Options) error { endCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - _ = client.EndSession(endCtx, sessionID) - fmt.Fprintf(os.Stderr, "\n✓ Session ended (%s)\n", truncateID(sessionID)) + if err := client.EndSession(endCtx, sessionID); err != nil { + fmt.Fprintf(os.Stderr, "\n⚠ Could not end session on backend: %v\n", err) + } else { + fmt.Fprintf(os.Stderr, "\n✓ Session ended (%s)\n", truncateID(sessionID)) + } os.RemoveAll(sessionDir) diff --git a/internal/sidecar/sidecar.go b/internal/sidecar/sidecar.go index f86e42d..4b75dce 100644 --- a/internal/sidecar/sidecar.go +++ b/internal/sidecar/sidecar.go @@ -5,10 +5,13 @@ package sidecar import ( "context" + "fmt" "log" "net" "os" "path/filepath" + "sync" + "sync/atomic" "time" agentv1 "github.com/kontext-dev/kontext-cli/gen/kontext/agent/v1" @@ -23,6 +26,9 @@ type Server struct { agentName string client *backend.Client cancel context.CancelFunc + + ingestFails atomic.Int64 + ingestWarnOnce sync.Once } // New creates a new sidecar server. @@ -120,20 +126,32 @@ func (s *Server) ingestEvent(ctx context.Context, req *EvaluateRequest) { } if err := s.client.IngestEvent(ctx, hookEvent); err != nil { - log.Printf("sidecar: ingest: %v", err) + n := s.ingestFails.Add(1) + s.ingestWarnOnce.Do(func() { + fmt.Fprintf(os.Stderr, "sidecar: event ingestion failed: %v\n", err) + }) + if n > 1 && n%10 == 0 { + fmt.Fprintf(os.Stderr, "sidecar: %d event ingestion failures (latest: %v)\n", n, err) + } } } func (s *Server) heartbeatLoop(ctx context.Context) { ticker := time.NewTicker(30 * time.Second) defer ticker.Stop() + consecutiveFails := 0 for { select { case <-ctx.Done(): return case <-ticker.C: if err := s.client.Heartbeat(ctx, s.sessionID); err != nil { - log.Printf("sidecar: heartbeat: %v", err) + consecutiveFails++ + if consecutiveFails == 1 || consecutiveFails == 3 { + fmt.Fprintf(os.Stderr, "sidecar: heartbeat failed (attempt %d): %v\n", consecutiveFails, err) + } + } else { + consecutiveFails = 0 } } }