-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathpriority_bulkhead_test.go
More file actions
162 lines (134 loc) · 3.71 KB
/
priority_bulkhead_test.go
File metadata and controls
162 lines (134 loc) · 3.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package resile
import (
"context"
"errors"
"sync"
"testing"
)
func TestPriorityBulkhead(t *testing.T) {
t.Parallel()
capacity := uint(10)
thresholds := map[Priority]float64{
PriorityLow: 0.5, // 50% utilization
PriorityStandard: 0.8, // 80% utilization
PriorityCritical: 1.0, // 100% utilization
}
bh := NewPriorityBulkhead(capacity, thresholds)
// Channels to coordinate goroutines
active := make(chan struct{})
release := make(chan struct{})
defer close(release)
fill := func(count int) {
for i := 0; i < count; i++ {
go func() {
_ = bh.Execute(WithPriority(context.Background(), PriorityCritical), func() error {
active <- struct{}{}
<-release
return nil
})
}()
<-active // Wait for it to be active inside the bulkhead
}
}
// Fill up to 50%
fill(5)
// Low priority should be shed now (utilization is 5/10 = 0.5)
err := bh.Execute(WithPriority(context.Background(), PriorityLow), func() error {
return nil
})
if !errors.Is(err, ErrShedLoad) {
t.Errorf("expected ErrShedLoad for low priority, got %v", err)
}
// Standard priority should still pass
err = bh.Execute(WithPriority(context.Background(), PriorityStandard), func() error {
return nil
})
if err != nil {
t.Errorf("expected no error for standard priority, got %v", err)
}
// Fill up to 80% (3 more)
fill(3)
// Standard priority should be shed now (utilization is 8/10 = 0.8)
err = bh.Execute(WithPriority(context.Background(), PriorityStandard), func() error {
return nil
})
if !errors.Is(err, ErrShedLoad) {
t.Errorf("expected ErrShedLoad for standard priority, got %v", err)
}
// Critical priority should still pass
err = bh.Execute(WithPriority(context.Background(), PriorityCritical), func() error {
return nil
})
if err != nil {
t.Errorf("expected no error for critical priority, got %v", err)
}
// Fill up to 100% (2 more)
fill(2)
// Critical priority should be full now
err = bh.Execute(WithPriority(context.Background(), PriorityCritical), func() error {
return nil
})
if !errors.Is(err, ErrBulkheadFull) {
t.Errorf("expected ErrBulkheadFull for critical priority, got %v", err)
}
}
func TestPriorityBulkheadDefaultPriority(t *testing.T) {
t.Parallel()
capacity := uint(10)
thresholds := map[Priority]float64{
PriorityStandard: 0.5,
}
bh := NewPriorityBulkhead(capacity, thresholds)
// Channels to coordinate goroutines
active := make(chan struct{})
release := make(chan struct{})
defer close(release)
// Fill up to 50%
for i := 0; i < 5; i++ {
go func() {
_ = bh.Execute(context.Background(), func() error {
active <- struct{}{}
<-release
return nil
})
}()
<-active
}
// Standard priority (default) should be shed
err := bh.Execute(context.Background(), func() error {
return nil
})
if !errors.Is(err, ErrShedLoad) {
t.Errorf("expected ErrShedLoad for default priority, got %v", err)
}
}
func TestPriorityBulkheadIntegration(t *testing.T) {
t.Parallel()
bh := NewPriorityBulkhead(10, map[Priority]float64{
PriorityLow: 0.1,
})
// Occupy 1 slot
active := make(chan struct{})
release := make(chan struct{})
var wg sync.WaitGroup
wg.Add(1)
go func() {
defer wg.Done()
_ = DoErr(context.Background(), func(ctx context.Context) error {
active <- struct{}{}
<-release
return nil
}, WithPriorityBulkheadInstance(bh))
}()
<-active
// Low priority should fail. Use WithMaxAttempts(1) to avoid retries.
err := DoErr(WithPriority(context.Background(), PriorityLow), func(ctx context.Context) error {
return nil
}, WithPriorityBulkheadInstance(bh), WithMaxAttempts(1))
if !errors.Is(err, ErrShedLoad) {
t.Errorf("expected ErrShedLoad, got %v", err)
}
// Trigger release before waiting
close(release)
wg.Wait()
}