feat(GAL): Add reset_and_backfill task for group action log#119355
Conversation
Add a task that clears backfilled GroupActionLogEntry rows (source="backfill:activity") for a group, invalidates derived data, and re-triggers the single-group backfill. Preserves live-written entries. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
| ) | ||
| return | ||
|
|
||
| invalidate_group_derived_data(group_id) |
There was a problem hiding this comment.
Bug: A race condition exists where process_group_log_task can run on an empty action log because it's scheduled before the backfill task that populates the log completes.
Severity: HIGH
Suggested Fix
The order of operations should be changed. First, delete the old GroupActionLogEntry entries. Then, schedule the backfill_group_action_log_for_group task. The call to invalidate_group_derived_data should be removed from this function, as the backfill process itself handles invalidation correctly with a cursor, which avoids the race condition.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: src/sentry/tasks/backfill_group_action_log.py#L74
Potential issue: The function `reset_and_backfill_group_action_log` calls
`invalidate_group_derived_data(group_id)` without a cursor. This immediately deletes the
`GroupDerivedData` row and schedules `process_group_log_task` to run asynchronously.
Subsequently, old log entries are deleted, and a new backfill task is scheduled. A race
condition exists where `process_group_log_task` can execute before the backfill task has
inserted the new data. This would cause the derived data to be rebuilt from an empty or
incomplete action log, leading to incorrect state. The backfilled entries would then be
added without triggering another reprocessing.
invalidate_group_derived_data() also triggers process_group_log_task which would reprocess stale data. Delete GroupDerivedData row directly instead — the backfill will rebuild derived state naturally when it runs. Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
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.
Reviewed by Cursor Bugbot for commit b9bc2ef. Configure here.
| }, | ||
| ) | ||
|
|
||
| backfill_group_action_log_for_group.delay(group_id=group_id) |
There was a problem hiding this comment.
Derived data not rebuilt
High Severity
reset_and_backfill_group_action_log deletes the group’s GroupDerivedData row, then only enqueues backfill_group_action_log_for_group. That backfill path calls invalidate_group_derived_data with a cursor, which schedules process_group_log_task only when it deletes an existing derived row. With no row left after reset, re-inserted backfill entries may never trigger derived recomputation, leaving derived state missing or stale despite the reset’s stated rebuild goal.
Reviewed by Cursor Bugbot for commit b9bc2ef. Configure here.
| ) | ||
| return | ||
|
|
||
| GroupDerivedData.objects.filter(group_id=group_id).delete() |
There was a problem hiding this comment.
Bug: The reset_and_backfill_group_action_log task pre-emptively deletes GroupDerivedData, which prevents the subsequent async backfill from triggering the necessary derived data rebuild task.
Severity: HIGH
Suggested Fix
Remove the initial GroupDerivedData.objects.filter(group_id=group_id).delete() call from the reset_and_backfill_group_action_log task. The existing logic within the async backfill process, specifically the call to invalidate_group_derived_data, should be sufficient to handle the deletion and subsequent reprocessing trigger. This ensures the condition for scheduling the rebuild task is met correctly.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: src/sentry/tasks/backfill_group_action_log.py#L74
Potential issue: The `reset_and_backfill_group_action_log` task at line 74
unconditionally deletes `GroupDerivedData` records before scheduling an asynchronous
backfill. The backfill process later calls `invalidate_group_derived_data`, which is
supposed to trigger a data rebuild by calling `process_group_log_task.delay()`. However,
this trigger is conditional on `invalidate_group_derived_data` deleting at least one
row. Since the data was already deleted, this condition is never met. As a result, the
derived data is not rebuilt after the backfill completes, leaving it in an unprocessed
state indefinitely, which defeats the purpose of the backfill task.
|
The bots comment on something I think might be okay - like that the derived state in this case wont be calculated as part of the backfill, but it will lazily get recreated anyway. Guess I could add a manual triggering for |


Summary
reset_and_backfill_group_action_log(group_id)task that clears previously backfilled entries and re-runs the backfill for a single groupsource="backfill:activity"— preserves live-written entries (from web, API, MCP, etc.)backfill_group_action_log_for_grouptaskUse case
When the translator logic changes or a backfill produced incorrect data, this provides a clean "redo" without losing real-time action log entries.
Test plan