IterateSnapshot creates a snapshot of all tasks and iterates over the copy. This is safer than Iterate() when you need to call queue methods inside the callback, as no locks are held during callback execution. Note: The snapshot may become stale during iteration if tasks are added/removed by other
(doFn func(task.Task))
| 1046 | // |
| 1047 | // Memory overhead: O(n) where n is the number of tasks in the queue. |
| 1048 | func (q *TaskQueue) IterateSnapshot(doFn func(task.Task)) { |
| 1049 | if doFn == nil { |
| 1050 | return |
| 1051 | } |
| 1052 | |
| 1053 | defer q.MeasureActionTime("IterateSnapshot")() |
| 1054 | |
| 1055 | // Create snapshot under lock |
| 1056 | snapshot := q.GetSnapshot() |
| 1057 | |
| 1058 | defer func() { |
| 1059 | if r := recover(); r != nil { |
| 1060 | q.logger.Warn("panic recovered in TaskQueue IterateSnapshot", |
| 1061 | slog.Any(pkg.LogKeyError, r), |
| 1062 | slog.String(pkg.LogKeyStack, string(debug.Stack())), |
| 1063 | slog.String(pkg.LogKeyQueue, q.Name), |
| 1064 | slog.Int(pkg.LogKeyTasksCount, len(snapshot)), |
| 1065 | ) |
| 1066 | } |
| 1067 | }() |
| 1068 | |
| 1069 | // Execute callbacks without holding any locks |
| 1070 | for _, t := range snapshot { |
| 1071 | doFn(t) |
| 1072 | } |
| 1073 | } |
| 1074 | |
| 1075 | // GetSnapshot returns a copy of all tasks in the queue. |
| 1076 | // This is useful for external iteration or processing without holding locks. |