| 234 | } |
| 235 | |
| 236 | func (tm *TaskManager) dequeueNextStartableLocked(preferredKey string) *Task { |
| 237 | if len(tm.activeTasks) >= tm.maxRunning { |
| 238 | return nil |
| 239 | } |
| 240 | |
| 241 | tryStartForKey := func(key string) *Task { |
| 242 | if _, active := tm.activeTasks[key]; active { |
| 243 | return nil |
| 244 | } |
| 245 | queue := tm.queue[key] |
| 246 | if len(queue) == 0 { |
| 247 | return nil |
| 248 | } |
| 249 | |
| 250 | next := queue[0] |
| 251 | tm.queue[key] = queue[1:] |
| 252 | if len(tm.queue[key]) == 0 { |
| 253 | delete(tm.queue, key) |
| 254 | } |
| 255 | tm.activeTasks[key] = next |
| 256 | return next |
| 257 | } |
| 258 | |
| 259 | if preferredKey != "" { |
| 260 | if next := tryStartForKey(preferredKey); next != nil { |
| 261 | return next |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | keys := make([]string, 0, len(tm.queue)) |
| 266 | for key := range tm.queue { |
| 267 | if key == preferredKey { |
| 268 | continue |
| 269 | } |
| 270 | keys = append(keys, key) |
| 271 | } |
| 272 | sort.Strings(keys) |
| 273 | |
| 274 | for _, key := range keys { |
| 275 | if next := tryStartForKey(key); next != nil { |
| 276 | return next |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | return nil |
| 281 | } |
| 282 | |
| 283 | func (tm *TaskManager) CancelTask(taskID string) error { |
| 284 | // First check queues and remove if found (fast operation, keep lock) |