Skip to content

Commit c11cc61

Browse files
committed
feat(usage): add PingCheckCtx for cancellable ping loops
PingCheck runs an unbounded ticker loop with no stop mechanism — once started, it emits ping events for the entire process lifetime. This prevents consumers from running ping under cancellation-aware constructs like leader election, where a pod that loses leadership needs its ping goroutines to stop cleanly. Without a stop signal, ex-leaders leak goroutines across every transition and continue emitting duplicate events from pods that should be quiet. Add PingCheckCtx(ctx, engineName, category, pingImmediately) alongside PingCheck. Same semantics, but the ticker loop selects on ctx.Done() and returns cleanly on cancellation. defer ticker.Stop() to avoid a leaked ticker on the cancellation path. Refactor PingCheck into a one-line wrapper around PingCheckCtx(context.Background(), ...) and mark it Deprecated in the godoc. Backward-compatible: the signature is unchanged, and under context.Background() ctx.Done() returns a nil channel that blocks forever, so the select degrades to the same forever-tick loop as before. Signed-off-by: Niladri Halder <niladri.halder26@gmail.com>
1 parent c2fca3a commit c11cc61

1 file changed

Lines changed: 23 additions & 25 deletions

File tree

usage/ping.go

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,7 @@
1-
/*
2-
Copyright 2023 The OpenEBS Authors.
3-
4-
Licensed under the Apache License, Version 2.0 (the "License");
5-
you may not use this file except in compliance with the License.
6-
You may obtain a copy of the License at
7-
8-
http://www.apache.org/licenses/LICENSE-2.0
9-
10-
Unless required by applicable law or agreed to in writing, software
11-
distributed under the License is distributed on an "AS IS" BASIS,
12-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
See the License for the specific language governing permissions and
14-
limitations under the License.
15-
*/
16-
171
package usage
182

193
import (
4+
"context"
205
"fmt"
216
"time"
227

@@ -35,8 +20,15 @@ const (
3520
minimumPingPeriod time.Duration = 1 * time.Hour
3621
)
3722

38-
// PingCheck sends ping events to Google Analytics
23+
// PingCheck sends ping events to Google Analytics on a fixed cadence.
3924
func PingCheck(engineName, category string, pingImmediately bool) {
25+
PingCheckCtx(context.Background(), engineName, category, pingImmediately)
26+
}
27+
28+
// PingCheckCtx sends ping events to Google Analytics on a fixed cadence,
29+
// returning when ctx is cancelled. If pingImmediately is true, one event is
30+
// sent before the ticker starts; subsequent events fire every getPingPeriod().
31+
func PingCheckCtx(ctx context.Context, engineName, category string, pingImmediately bool) {
4032
// Create a new usage field
4133
u := New()
4234

@@ -48,14 +40,20 @@ func PingCheck(engineName, category string, pingImmediately bool) {
4840
Send()
4941
}
5042

51-
duration := getPingPeriod()
52-
ticker := time.NewTicker(duration)
53-
for range ticker.C {
54-
// Ping periodically, starting at 'duration'.
55-
u.CommonBuild(engineName).
56-
InstallBuilder(true).
57-
SetCategory(category).
58-
Send()
43+
ticker := time.NewTicker(getPingPeriod())
44+
defer ticker.Stop()
45+
46+
for {
47+
select {
48+
case <-ctx.Done():
49+
return
50+
case <-ticker.C:
51+
// Ping periodically.
52+
u.CommonBuild(engineName).
53+
InstallBuilder(true).
54+
SetCategory(category).
55+
Send()
56+
}
5957
}
6058
}
6159

0 commit comments

Comments
 (0)