From 889c3c8f8d3e52656b247bd9750d040cff249b4f Mon Sep 17 00:00:00 2001 From: aliamerj Date: Tue, 16 Sep 2025 21:06:54 +0300 Subject: [PATCH] fix(engine): avoid deadlock when stopping engine during debug bundle --- client/internal/engine.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/client/internal/engine.go b/client/internal/engine.go index 204ba65bb..3ce21ffbd 100644 --- a/client/internal/engine.go +++ b/client/internal/engine.go @@ -927,12 +927,16 @@ func (e *Engine) receiveJobEvents() { } func (e *Engine) handleBundle(params *mgmProto.BundleParameters) (*mgmProto.JobResponse_Bundle, error) { - // todo: @Vic, do we need to latest sync response all the time here or could it be nil in the debug bundle? - // todo: e.GetLatestSyncResponse() is exported and has been protected by a mutex. If you will use handleBundle in - // also protected context then will be deadlock - syncResponse, err := e.GetLatestSyncResponse() - if err != nil { - return nil, fmt.Errorf("get latest sync response: %w", err) + // Access sync response directly without calling exported method to avoid deadlock + // This is safe because we're in a goroutine that doesn't hold the syncMsgMux + var syncResponse *mgmProto.SyncResponse + if e.persistSyncResponse && e.latestSyncResponse != nil { + log.Debugf("Retrieving latest sync response with size %d bytes", proto.Size(e.latestSyncResponse)) + if sr, ok := proto.Clone(e.latestSyncResponse).(*mgmProto.SyncResponse); ok { + syncResponse = sr + } else { + return nil, fmt.Errorf("failed to clone sync response") + } } if syncResponse == nil {