feat(sync): add delayed task submission for throttling#1506
feat(sync): add delayed task submission for throttling#1506
Conversation
|
|
@sentry review |
|
@cursor review |
0f6f4b9 to
a4428e0
Compare
a4428e0 to
344664e
Compare
Add sentry__bgworker_submit_delayed() to defer task execution by a given number of milliseconds. Tasks are sorted by readiness time using monotonic timestamps, so a ready delayed task is not bypassed by a later-submitted immediate task. On shutdown, tasks that exceed the deadline (started + timeout) are pruned while the rest execute normally. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The flush marker now uses the last task's deadline (capped at the flush timeout) so it sorts after all current tasks including delayed ones. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract the core submission logic into submit_at which takes an absolute execute_after time. submit and submit_delayed become thin wrappers. Use submit_at in bgworker_delayed_tasks to pin all tasks to a single base timestamp, making the test ordering deterministic regardless of OS preemption between submissions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move delayed task cleanup from the shutdown pre-prune pass into the worker thread itself. When the worker encounters a delayed task that is not yet ready and shutdown has been signaled, it discards all remaining tasks. This catches tasks submitted during execution that the one-time pre-prune in shutdown could not see. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of explicitly discarding delayed tasks in worker_thread, teach sentry__bgworker_is_done to treat pending delayed tasks as done when !running. Remaining tasks are cleaned up by decref. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3bd8b5d to
c28a807
Compare
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a delayed task's deadline exceeds the flush timeout, don't use it to delay the flush sentinel. Such tasks cannot complete within the timeout anyway, and capping to the timeout caused the sentinel to race with the caller's deadline. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@sentry review |
|
@cursor review |
The previous fix only checked last_task, so a far-future tail caused delay_ms=0 which skipped eligible delayed tasks earlier in the queue. Walk from first_task to find the last task due within the timeout. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Large delay_ms values could wrap execute_after into the past, causing immediate execution. Use saturating addition capped at UINT64_MAX. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@cursor review |
submit_at sorted insertion could insert before first_task while it was executing without the lock held, causing the worker loop to skip the pop and re-execute the task on the next iteration. Track current_task so sorted insertion starts after it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
submit_delayed reads the clock again internally, so the sentinel ended up scheduled later than intended. Use submit_at with the absolute timestamp to eliminate drift between queue scan and submit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@cursor review |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| // insert sorted by execute_after; skip past current_task which | ||
| // may be executing without the lock held | ||
| sentry_bgworker_task_t *prev = bgw->current_task; | ||
| sentry_bgworker_task_t *cur = prev ? prev->next_task : bgw->first_task; |
There was a problem hiding this comment.
Use-after-free accessing freed task pointer
High Severity
The insertion logic at line 513 accesses current_task->next_task, but that next task may have been freed by sentry__bgworker_foreach_matching. When foreach_matching removes and frees the task pointed to by next_task, the pointer becomes stale. Subsequent insertions dereference this freed memory, causing a use-after-free that can crash the program. This occurs because foreach_matching decrements the task's refcount (potentially freeing it), but never updates the next_task pointer in current_task.


Add
sentry__bgworker_submit_delayed()to allow deferring task execution by a given number of milliseconds. This paves the road for HTTP retries that should be first throttled on startup (similar to Cocoa/iOS and Java/Android SDKs that throttle HTTP retries by 100ms) and then scheduled with exponential backoff (15min, 30min, 1h, 2h, ...).Required for:
#skip-changelog (internal)