| 535 | } |
| 536 | |
| 537 | func (rt *AgentTaskRuntime) CleanupScope(scopeID string) map[string]int { |
| 538 | report := map[string]int{"active_tasks_stopped": 0, "tasks_removed": 0} |
| 539 | for { |
| 540 | rt.mu.Lock() |
| 541 | var children []*AgentTaskRecord |
| 542 | for _, record := range rt.records { |
| 543 | if record.ParentScopeID == scopeID { |
| 544 | children = append(children, record) |
| 545 | } |
| 546 | } |
| 547 | rt.mu.Unlock() |
| 548 | if len(children) == 0 { |
| 549 | break |
| 550 | } |
| 551 | for _, record := range children { |
| 552 | if _, terminal := terminalTaskStatuses[record.Status]; !terminal { |
| 553 | report["active_tasks_stopped"]++ |
| 554 | rt.StopTask(record.TaskID, record.ParentScopeID) |
| 555 | } |
| 556 | child := rt.CleanupScope(record.TaskID) |
| 557 | report["active_tasks_stopped"] += child["active_tasks_stopped"] |
| 558 | report["tasks_removed"] += child["tasks_removed"] |
| 559 | rt.mu.Lock() |
| 560 | if cancel := rt.workers[record.TaskID]; cancel != nil { |
| 561 | cancel() |
| 562 | } |
| 563 | delete(rt.workers, record.TaskID) |
| 564 | delete(rt.workerSpecs, record.TaskID) |
| 565 | removed := rt.unregisterRecordLocked(record.TaskID) |
| 566 | if removed != nil { |
| 567 | rt.cancelRecordCleanupLocked(record.TaskID) |
| 568 | rt.forgetTaskIdentityLocked(record.TaskID) |
| 569 | report["tasks_removed"]++ |
| 570 | } |
| 571 | delete(rt.scopes, record.TaskID) |
| 572 | rt.mu.Unlock() |
| 573 | } |
| 574 | } |
| 575 | rt.mu.Lock() |
| 576 | delete(rt.scopes, scopeID) |
| 577 | delete(rt.notifications, scopeID) |
| 578 | rt.mu.Unlock() |
| 579 | return report |
| 580 | } |
| 581 | |
| 582 | func (rt *AgentTaskRuntime) DrainPendingNotifications(scopeID string) []map[string]any { |
| 583 | rt.mu.Lock() |