Skip to content

Commit fa3af08

Browse files
crobert-1XinRanZhAWS
authored andcommitted
[exporter/signalfx] Fix memory leak on shutdown (open-telemetry#30887)
**Description:** <Describe what has changed.> <!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> `goleak` was detecting leaking goroutines in tests, this attempts to resolve. I found what appeared to be a couple races but can't reproduce locally so I'll run CI a few times to ensure this works as expected. Changes in PR: 1. Add correlation client Shutdown function that blocks on the waitgroup. This is the main fix of this PR that should fix the leaking goroutines. 2. Re-organize the shutdown process of the apm client correlation test suite to properly synchronize the shutting down process. 3. Fix typo 4. Add goleak checks to exporter/signalfx/internal/correlation` and `exporter/signalfx/internal/apm/correlations` **Link to tracking Issue:** <Issue number if applicable> Resolves open-telemetry#30864 open-telemetry#30438 **Testing:** <Describe what testing was performed and which tests were added.> All existing and added tests should be passing. Since this has only failed in CI I'm going to try to run it a few times before marking as ready for review.
1 parent efc1735 commit fa3af08

File tree

8 files changed

+86
-11
lines changed

8 files changed

+86
-11
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: bug_fix
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: signalfxexporter
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Fix memory leak in shutdown
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [30864, 30438]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []

exporter/signalfxexporter/internal/apm/correlations/client.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type CorrelationClient interface {
4444
Delete(*Correlation, SuccessfulDeleteCB)
4545
Get(dimName string, dimValue string, cb SuccessfulGetCB)
4646
Start()
47+
Shutdown()
4748
}
4849

4950
type request struct {
@@ -387,3 +388,9 @@ func (cc *Client) Start() {
387388
go cc.processChan()
388389
go cc.processRetryChan()
389390
}
391+
392+
// Shutdown the client. This will block until the context's cancel
393+
// function is complete.
394+
func (cc *Client) Shutdown() {
395+
cc.wg.Wait()
396+
}

exporter/signalfxexporter/internal/apm/correlations/client_test.go

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -124,18 +124,14 @@ func makeHandler(t *testing.T, corCh chan<- *request, forcedRespCode *atomic.Val
124124
})
125125
}
126126

127-
func setup(t *testing.T) (CorrelationClient, chan *request, *atomic.Value, *atomic.Value, context.CancelFunc) {
127+
func setup(t *testing.T) (CorrelationClient, *httptest.Server, chan *request, *atomic.Value, *atomic.Value, context.CancelFunc, context.Context) {
128128
serverCh := make(chan *request, 100)
129129

130130
var forcedRespCode atomic.Value
131131
var forcedRespPayload atomic.Value
132132
server := httptest.NewServer(makeHandler(t, serverCh, &forcedRespCode, &forcedRespPayload))
133133

134134
ctx, cancel := context.WithCancel(context.Background())
135-
go func() {
136-
<-ctx.Done()
137-
server.Close()
138-
}()
139135

140136
serverURL, err := url.Parse(server.URL)
141137
if err != nil {
@@ -176,13 +172,20 @@ func setup(t *testing.T) (CorrelationClient, chan *request, *atomic.Value, *atom
176172
}
177173
client.Start()
178174

179-
return client, serverCh, &forcedRespCode, &forcedRespPayload, cancel
175+
return client, server, serverCh, &forcedRespCode, &forcedRespPayload, cancel, ctx
176+
}
177+
178+
func teardown(ctx context.Context, client CorrelationClient, server *httptest.Server, serverCh chan *request, cancel context.CancelFunc) {
179+
close(serverCh)
180+
cancel()
181+
<-ctx.Done()
182+
client.Shutdown()
183+
server.Close()
180184
}
181185

182186
func TestCorrelationClient(t *testing.T) {
183-
client, serverCh, forcedRespCode, forcedRespPayload, cancel := setup(t)
184-
defer close(serverCh)
185-
defer cancel()
187+
client, server, serverCh, forcedRespCode, forcedRespPayload, cancel, ctx := setup(t)
188+
defer teardown(ctx, client, server, serverCh, cancel)
186189

187190
for _, correlationType := range []Type{Service, Environment} {
188191
for _, op := range []string{http.MethodPut, http.MethodDelete} {
@@ -242,7 +245,7 @@ func TestCorrelationClient(t *testing.T) {
242245
client.Correlate(testData, CorrelateCB(func(_ *Correlation, _ error) {}))
243246
// sending the testData twice tests deduplication, since the 500 status
244247
// will trigger retries, and the requests should be deduped and the
245-
// TotalRertriedUpdates should still only be 5
248+
// TotalRetriedUpdates should still only be 5
246249
client.Correlate(testData, CorrelateCB(func(_ *Correlation, _ error) {}))
247250

248251
cors := waitForCors(serverCh, 1, 4)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package correlations
5+
6+
import (
7+
"testing"
8+
9+
"go.uber.org/goleak"
10+
)
11+
12+
// The IgnoreTopFunction call prevents catching the leak generated by opencensus
13+
// defaultWorker.Start which at this time is part of the package's init call.
14+
// See https://github.com/census-instrumentation/opencensus-go/issues/1191 for more information.
15+
func TestMain(m *testing.M) {
16+
goleak.VerifyTestMain(m, goleak.IgnoreTopFunction("go.opencensus.io/stats/view.(*worker).start"))
17+
}

exporter/signalfxexporter/internal/apm/tracetracker/tracker_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ type correlationTestClient struct {
8585
correlateCounter int64
8686
}
8787

88-
func (c *correlationTestClient) Start() { /*no-op*/ }
88+
func (c *correlationTestClient) Start() { /*no-op*/ }
89+
func (c *correlationTestClient) Shutdown() { /*no-op*/ }
8990
func (c *correlationTestClient) Get(_ string, dimValue string, cb correlations.SuccessfulGetCB) {
9091
atomic.AddInt64(&c.getCounter, 1)
9192
go func() {

exporter/signalfxexporter/internal/correlation/correlation.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ func (cor *Tracker) Shutdown(_ context.Context) error {
137137
if cor != nil {
138138
if cor.correlation != nil {
139139
cor.correlation.cancel()
140+
cor.correlation.CorrelationClient.Shutdown()
140141
}
141142

142143
if cor.pTicker != nil {

exporter/signalfxexporter/internal/correlation/correlation_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ func TestTrackerStart(t *testing.T) {
8686
} else {
8787
require.NoError(t, err)
8888
}
89+
90+
assert.NoError(t, tracker.Shutdown(context.Background()))
8991
})
9092
}
9193
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright The OpenTelemetry Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package correlation
5+
6+
import (
7+
"testing"
8+
9+
"go.uber.org/goleak"
10+
)
11+
12+
// The IgnoreTopFunction call prevents catching the leak generated by opencensus
13+
// defaultWorker.Start which at this time is part of the package's init call.
14+
// See https://github.com/census-instrumentation/opencensus-go/issues/1191 for more information.
15+
func TestMain(m *testing.M) {
16+
goleak.VerifyTestMain(m, goleak.IgnoreTopFunction("go.opencensus.io/stats/view.(*worker).start"))
17+
}

0 commit comments

Comments
 (0)