Skip to content

Commit 9c37c67

Browse files
committed
Redesign of the configuration
Compiler errors in the examples are inrended to demonstrate setting nil contexts.
1 parent 3baddf8 commit 9c37c67

12 files changed

Lines changed: 1079 additions & 216 deletions

File tree

CONFIG_MIGRATION.md

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
# Worker Config Migration Guide
2+
3+
## Overview
4+
5+
The `Config` struct in the worker package has been refactored to use a builder pattern with private fields, setter methods, and comprehensive error accumulation. This provides better encapsulation, validation at the point of setting values, and the ability to detect multiple configuration errors at once.
6+
7+
## Key Changes
8+
9+
### 1. Private Fields
10+
11+
All configuration fields are now private and can only be accessed through getter methods:
12+
13+
- `Context()` - returns the configured context
14+
- `Rate()` - returns the rate limit
15+
- `Burst()` - returns the burst capacity
16+
- `Timeout()` - returns the timeout duration
17+
- `ShutdownTimeout()` - returns the shutdown timeout
18+
- `ErrorHandler()` - returns the error handler
19+
20+
### 2. Constructor Function
21+
22+
Instead of creating a struct literal, use the constructor:
23+
24+
```go
25+
// Old
26+
cfg := worker.Config{
27+
Rate: 10,
28+
Burst: 20,
29+
}
30+
31+
// New
32+
cfg := worker.NewConfig(context.Background()).
33+
SetRate(10).
34+
SetBurst(20)
35+
```
36+
37+
### 3. Method Chaining
38+
39+
All setter methods return `*Config` for fluent interface:
40+
41+
```go
42+
cfg := worker.NewConfig(ctx).
43+
SetRate(100).
44+
SetBurst(200).
45+
SetTimeout(5 * time.Second).
46+
SetShutdownTimeout(10 * time.Second).
47+
SetErrorHandler(errorHandler)
48+
```
49+
50+
### 4. Error Accumulation
51+
52+
Multiple validation errors are accumulated using `errors.Join`:
53+
54+
```go
55+
cfg := worker.NewConfig(nil).
56+
SetRate(-1). // Error: rate must be positive
57+
SetBurst(-5). // Error: burst must be positive
58+
SetTimeout(-1) // Error: timeout must be positive
59+
60+
if err := cfg.Error(); err != nil {
61+
// err contains ALL validation errors, not just the last one
62+
fmt.Println(err)
63+
// Output:
64+
// rate must be positive, got -1
65+
// burst must be positive, got -5
66+
// timeout must be positive, got -1s
67+
}
68+
```
69+
70+
### 5. Automatic Error Checking in Constructors
71+
72+
Both `worker.New()` and `worker.NewWorkerPool()` automatically check for configuration errors:
73+
74+
```go
75+
cfg := worker.NewConfig(context.Background()).
76+
SetRate(-10). // Invalid!
77+
SetBurst(-5) // Invalid!
78+
79+
// Even if you forget to check cfg.Error()...
80+
w, err := worker.New(cfg) // This will return the configuration errors
81+
if err != nil {
82+
// err contains all validation errors from the config
83+
}
84+
```
85+
86+
### 6. Immediate Validation
87+
88+
Values are validated when set, not when the worker is created:
89+
90+
```go
91+
cfg := worker.NewConfig(context.Background()).
92+
SetRate(-10) // Validation happens here
93+
94+
// Check for errors immediately
95+
if err := cfg.Error(); err != nil {
96+
// Handle configuration error
97+
}
98+
```
99+
100+
## Migration Examples
101+
102+
### Basic Migration
103+
104+
```go
105+
// Old
106+
cfg := worker.Config{
107+
Context: ctx,
108+
Rate: 10,
109+
Burst: 20,
110+
Timeout: 5 * time.Second,
111+
ShutdownTimeout: 10 * time.Second,
112+
}
113+
w, err := worker.New(cfg)
114+
115+
// New
116+
cfg := worker.NewConfig(ctx).
117+
SetRate(10).
118+
SetBurst(20).
119+
SetTimeout(5 * time.Second).
120+
SetShutdownTimeout(10 * time.Second)
121+
122+
if err := cfg.Error(); err != nil {
123+
// Handle configuration errors
124+
return err
125+
}
126+
w, err := worker.New(cfg)
127+
```
128+
129+
### Using Default Config
130+
131+
```go
132+
// Old
133+
cfg := worker.DefaultConfig()
134+
135+
// New (same function, but returns *Config now)
136+
cfg := worker.DefaultConfig()
137+
```
138+
139+
### Worker Pool Migration
140+
141+
```go
142+
// Old
143+
pool, err := worker.NewWorkerPool(5, worker.Config{
144+
Rate: 10,
145+
Burst: 20,
146+
})
147+
148+
// New
149+
cfg := worker.NewConfig(context.Background()).
150+
SetRate(10).
151+
SetBurst(20)
152+
153+
if err := cfg.Error(); err != nil {
154+
return err
155+
}
156+
pool, err := worker.NewWorkerPool(5, cfg)
157+
```
158+
159+
## Validation Rules
160+
161+
1. **Context**: Cannot be nil (defaults to context.Background() in constructor)
162+
2. **Rate**: Must be positive (> 0)
163+
3. **Burst**: Must be positive and >= rate
164+
4. **Timeout**: Must be positive duration
165+
5. **ShutdownTimeout**: Must be positive duration
166+
6. **ErrorHandler**: Can be nil (errors will be ignored)
167+
168+
## Special Behaviors
169+
170+
### Auto-adjustment of Burst
171+
172+
When setting rate, if the current burst is less than the new rate, burst is automatically adjusted:
173+
174+
```go
175+
cfg := worker.NewConfig(context.Background()).
176+
SetBurst(50). // Set burst to 50
177+
SetRate(100) // Rate is 100, burst auto-adjusts to 100
178+
179+
// cfg.Burst() returns 100, not 50
180+
```
181+
182+
### Error Checking Options
183+
184+
You can check errors at any point:
185+
186+
```go
187+
// Option 1: Check after all setters (recommended for early feedback)
188+
cfg := worker.NewConfig(ctx).
189+
SetRate(10).
190+
SetBurst(20)
191+
192+
if err := cfg.Error(); err != nil {
193+
// Handle error
194+
}
195+
196+
// Option 2: Check via Validate() (same as Error())
197+
if err := cfg.Validate(); err != nil {
198+
// Handle error
199+
}
200+
201+
// Option 3: Let New() check for you (safety net)
202+
w, err := worker.New(cfg) // Automatically returns error if config is invalid
203+
204+
// Note: Even if you forget to check cfg.Error(), New() and NewWorkerPool()
205+
// will catch configuration errors and return them, preventing invalid workers
206+
// from being created.
207+
```
208+
209+
## Benefits of the New Approach
210+
211+
1. **Better Encapsulation**: Private fields prevent direct manipulation
212+
2. **Immediate Validation**: Errors are caught when values are set
213+
3. **Error Accumulation**: All validation errors are reported, not just the first one
214+
4. **Fluent Interface**: Clean, readable configuration code
215+
5. **Type Safety**: Setter methods ensure correct types
216+
6. **Immutable After Creation**: Once passed to New(), config cannot be accidentally modified
217+
7. **Safety Net**: `New()` and `NewWorkerPool()` automatically check for configuration errors, preventing creation of invalid workers even if the user forgets to check
218+
219+
## Backward Compatibility
220+
221+
This is a breaking change. Code using the old `Config` struct literal syntax must be updated to use the new setter methods.

commands.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ func EnqueueWaiting(wp WorkProcessor, task Task) error {
3737
select {
3838
case err := <-done:
3939
return err
40-
case <-time.After(wp.config().Timeout):
41-
return TimeoutError{Duration: wp.config().Timeout}
40+
case <-time.After(wp.config().Timeout()):
41+
return TimeoutError{Duration: wp.config().Timeout()}
4242
}
4343
}
4444

@@ -90,4 +90,3 @@ func EnqueueAwaiting(wp WorkProcessor, task Task, timeout time.Duration) (Awaite
9090
func Stop(wp WorkProcessor) error {
9191
return wp.stop()
9292
}
93-

0 commit comments

Comments
 (0)