• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pace / bricks / 12827718001

17 Jan 2025 10:57AM UTC coverage: 56.909% (-0.3%) from 57.237%
12827718001

Pull #384

github

monstermunchkin
Satisfy linters
Pull Request #384: Extend linting

478 of 946 new or added lines in 109 files covered. (50.53%)

133 existing lines in 53 files now uncovered.

5667 of 9958 relevant lines covered (56.91%)

21.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/pkg/routine/instance.go
1
// Copyright © 2020 by PACE Telematics GmbH. All rights reserved.
2

3
package routine
4

5
import (
6
        "context"
7
        "fmt"
8
        "time"
9

10
        "github.com/getsentry/sentry-go"
11
        exponential "github.com/jpillora/backoff"
12

13
        "github.com/pace/bricks/maintenance/errors"
14
        "github.com/pace/bricks/pkg/lock/redis"
15
)
16

17
type routineThatKeepsRunningOneInstance struct {
18
        Name    string
19
        Routine func(context.Context)
20

21
        lockTTL       time.Duration
22
        retryInterval time.Duration
23
        backoff       combinedExponentialBackoff
24
        num           int64
25
}
26

27
func (r *routineThatKeepsRunningOneInstance) Run(ctx context.Context) {
×
28
        // The retry interval is used if we did not get the lock because some
×
29
        // other caller got it. The exponential backoff is used if we encounter
×
30
        // problems with obtaining the lock, like the Redis not being available.
×
31
        // The retry interval is also used if the routine returned regularly, to
×
32
        // avoid uncontrollably short restart cycles. If the routine panicked we
×
33
        // use exponential backoff as well.
×
34
        r.lockTTL = cfg.RedisLockTTL
×
35
        r.retryInterval = r.lockTTL / 5
×
36
        r.backoff = combinedExponentialBackoff{
×
37
                "lock":    &exponential.Backoff{Min: r.retryInterval, Max: 10 * time.Minute},
×
38
                "routine": &exponential.Backoff{Min: r.retryInterval, Max: 10 * time.Minute},
×
39
        }
×
40

×
NEW
41
        r.num, _ = ctx.Value(ctxNumKey{}).(int64)
×
NEW
42

×
43
        var tryAgainIn time.Duration // zero on first run
×
NEW
44

×
45
        for {
×
46
                select {
×
47
                case <-ctx.Done():
×
48
                        return
×
49
                case <-time.After(tryAgainIn):
×
50
                }
51
                // Make sure to cancel the singleRunCtx so that the lock is released
52
                // after the routine returned.
53
                singleRunCtx, cancel := context.WithCancel(ctx)
×
54
                tryAgainIn = r.singleRun(singleRunCtx)
×
NEW
55

×
UNCOV
56
                cancel()
×
57
        }
58
}
59

60
// Performs a single run. That is, to try to obtain the lock and run the routine
61
// until it returns. Return the backoff duration after which another single run
62
// should be performed.
63
func (r *routineThatKeepsRunningOneInstance) singleRun(ctx context.Context) time.Duration {
×
64
        l := redis.NewLock("routine:lock:"+r.Name, redis.SetTTL(r.lockTTL))
×
NEW
65

×
66
        lockCtx, cancel, err := l.AcquireAndKeepUp(ctx)
×
67
        if err != nil {
×
68
                go errors.Handle(ctx, err) // report error to Sentry, non-blocking
×
69
                return r.backoff.Duration("lock")
×
70
        }
×
71

72
        if lockCtx != nil {
×
73
                defer cancel()
×
NEW
74

×
75
                routinePanicked := true
×
NEW
76

×
77
                func() {
×
78
                        defer errors.HandleWithCtx(ctx, fmt.Sprintf("routine %d", r.num)) // handle panics
×
79

×
80
                        span := sentry.StartSpan(lockCtx, "function", sentry.WithDescription(fmt.Sprintf("routine %d", r.num)))
×
81
                        defer span.Finish()
×
82

×
83
                        r.Routine(span.Context())
×
NEW
84

×
85
                        routinePanicked = false
×
86
                }()
×
87

88
                if routinePanicked {
×
89
                        return r.backoff.Duration("routine")
×
90
                }
×
91
        }
92

93
        r.backoff.ResetAll()
×
NEW
94

×
UNCOV
95
        return r.retryInterval
×
96
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc