|
| 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. |
0 commit comments