75f3dd141c
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CI and Release / lint-frontend (push) Has been cancelled
CI and Release / dockerfile-scan (push) Has been cancelled
CI and Release / test-frontend (push) Has been cancelled
CI and Release / lint-verification-agent (push) Has been cancelled
CI and Release / test-verification-agent (push) Has been cancelled
CI and Release / e2e-verification-agent (push) Has been cancelled
CI and Release / test-backend (push) Has been cancelled
CI and Release / build-dev-image (push) Has been cancelled
CI and Release / push-dev-image (push) Has been cancelled
CI and Release / build-image (push) Has been cancelled
CI and Release / build-verification-image (push) Has been cancelled
CI and Release / determine-version (push) Has been cancelled
CI and Release / push-image (push) Has been cancelled
CI and Release / push-verification-image (12) (push) Has been cancelled
CI and Release / lint-backend (push) Has been cancelled
CI and Release / push-verification-image (17) (push) Has been cancelled
CI and Release / push-verification-image (18) (push) Has been cancelled
CI and Release / release (push) Has been cancelled
CI and Release / publish-helm-chart (push) Has been cancelled
CI and Release / push-verification-image (13) (push) Has been cancelled
CI and Release / push-verification-image (14) (push) Has been cancelled
CI and Release / push-verification-image (15) (push) Has been cancelled
CI and Release / push-verification-image (16) (push) Has been cancelled
110 lines
2.3 KiB
Go
110 lines
2.3 KiB
Go
package telemetry
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
"math/rand/v2"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"databasus-backend/internal/config"
|
|
)
|
|
|
|
const (
|
|
defaultWarmupDuration = 1 * time.Minute
|
|
defaultSuccessInterval = 24 * time.Hour
|
|
defaultJitter = 10 * time.Minute
|
|
defaultInitialBackoff = 1 * time.Minute
|
|
defaultMaxBackoff = 24 * time.Hour
|
|
)
|
|
|
|
type TelemetryBackgroundService struct {
|
|
telemetryService *TelemetryService
|
|
logger *slog.Logger
|
|
|
|
WarmupDuration time.Duration
|
|
SuccessInterval time.Duration
|
|
Jitter time.Duration
|
|
InitialBackoff time.Duration
|
|
MaxBackoff time.Duration
|
|
|
|
hasRun atomic.Bool
|
|
}
|
|
|
|
func NewTelemetryBackgroundService(
|
|
telemetryService *TelemetryService,
|
|
logger *slog.Logger,
|
|
) *TelemetryBackgroundService {
|
|
return &TelemetryBackgroundService{
|
|
telemetryService: telemetryService,
|
|
logger: logger,
|
|
WarmupDuration: defaultWarmupDuration,
|
|
SuccessInterval: defaultSuccessInterval,
|
|
Jitter: defaultJitter,
|
|
InitialBackoff: defaultInitialBackoff,
|
|
MaxBackoff: defaultMaxBackoff,
|
|
}
|
|
}
|
|
|
|
func (s *TelemetryBackgroundService) Run(ctx context.Context) {
|
|
if s.hasRun.Swap(true) {
|
|
panic(fmt.Sprintf("%T.Run() called multiple times", s))
|
|
}
|
|
|
|
if config.GetEnv().IsDisableAnonymousTelemetry {
|
|
s.logger.Info("anonymous telemetry is disabled")
|
|
return
|
|
}
|
|
|
|
if !sleep(ctx, s.WarmupDuration) {
|
|
return
|
|
}
|
|
|
|
backoff := s.InitialBackoff
|
|
|
|
for {
|
|
err := s.telemetryService.BuildAndSend(ctx)
|
|
|
|
var nextDelay time.Duration
|
|
if err != nil {
|
|
s.logger.Warn("telemetry ping failed", "error", err, "next_retry", backoff)
|
|
nextDelay = backoff
|
|
backoff = min(backoff*2, s.MaxBackoff)
|
|
} else {
|
|
backoff = s.InitialBackoff
|
|
nextDelay = s.SuccessInterval + jitter(s.Jitter)
|
|
}
|
|
|
|
if !sleep(ctx, nextDelay) {
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// sleep returns false when ctx is cancelled before d elapses.
|
|
func sleep(ctx context.Context, d time.Duration) bool {
|
|
if d <= 0 {
|
|
return ctx.Err() == nil
|
|
}
|
|
|
|
timer := time.NewTimer(d)
|
|
defer timer.Stop()
|
|
|
|
select {
|
|
case <-ctx.Done():
|
|
return false
|
|
case <-timer.C:
|
|
return true
|
|
}
|
|
}
|
|
|
|
// jitter returns a random offset in [-d, +d]. With d == 0 it returns 0.
|
|
func jitter(d time.Duration) time.Duration {
|
|
if d <= 0 {
|
|
return 0
|
|
}
|
|
|
|
return time.Duration(rand.Int64N(int64(2*d))) - d
|
|
}
|