Skip to content

Conversation

@cathteng
Copy link
Member

If there is a conflict when we attempt to create a WorkflowActionGroupStatus row, that means another process has already successfully created the row and is going to fire a notification.

We should not fire an additional notification with the workflow+action that conflicted because we would not be respecting the action interval.

@cathteng cathteng requested a review from a team as a code owner November 25, 2025 20:02
@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Nov 25, 2025
Comment on lines -122 to -126
all_statuses = WorkflowActionGroupStatus.objects.bulk_create(
missing_statuses,
batch_size=1000,
ignore_conflicts=True,
)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately the best way to find the rows that were not created was to use a SQL query. Django's bulk_create doesn't have a nice way to only populate PKs in the return list for successful creates that didn't conflict

@codecov
Copy link

codecov bot commented Nov 25, 2025

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
2982 1 2981 55
View the top 1 failed test(s) by shortest run time
tests.sentry.core.endpoints.test_organization_index.OrganizationsCreateTest::test_valid_slugs
Stack Traces | 1.71s run time
#x1B[1m#x1B[.../core/endpoints/test_organization_index.py#x1B[0m:190: in test_valid_slugs
    response = self.get_success_response(name=input_slug, slug=input_slug)
#x1B[1m#x1B[.../sentry/testutils/cases.py#x1B[0m:628: in get_success_response
    assert_status_code(response, 200, 300)
#x1B[1m#x1B[.../sentry/testutils/asserts.py#x1B[0m:47: in assert_status_code
    assert minimum <= response.status_code < maximum, (
#x1B[1m#x1B[31mE   AssertionError: (500, b'{"detail":"Internal Error","errorId":null}')#x1B[0m
#x1B[1m#x1B[31mE   assert 500 < 300#x1B[0m
#x1B[1m#x1B[31mE    +  where 500 = <Response status_code=500, "application/json">.status_code#x1B[0m

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

Comment on lines 235 to 236
When(id=action_id, then=Value(list(workflow_ids)[0]))
for action_id, workflow_ids in action_to_workflows_ids.items()

This comment was marked as outdated.

Copy link
Member

@kcons kcons left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lg, see notes.

workflow_id_cases = [
When(id=action_id, then=Value(workflow_id))
for action_id, workflow_id in action_to_workflow_ids.items()
When(id=action_id, then=Value(list(workflow_ids)[0]))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe min to make it consistently choose the eldest workflow, then a comment above noting that the choice of 'min' is arbitrary? I think calling out nuances like this can help some future debugging effort.

now: datetime, statuses_to_update: set[int], missing_statuses: list[WorkflowActionGroupStatus]
) -> None:
WorkflowActionGroupStatus.objects.filter(
) -> tuple[int, int, list[tuple[int, int]]]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

document what we're returning; this is not an intuitive type.

with connection.cursor() as cursor:
# Build values for batch insert
values_placeholders = []
values_data = []
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bulk_create has a batch size because there are statement size limits. I don't know that we expect to hit them, I assume our expected upper end is hundreds here, but seems worth noting.

)

# if statuses were not created for some reason, we should not fire for them
for workflow_id, action_id in uncreated_statuses:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we believe them to be conflicting, maybe 'conflicted_statuses' and this all is a bit easier to understand. If there are reasons beyond conflict where we expect them to not be created, it's less clear to me why they shouldn't be fired.

for workflow_id, action_id in uncreated_statuses:
action_to_workflows_ids[action_id].remove(workflow_id)
if not action_to_workflows_ids[action_id]:
action_to_workflows_ids.pop(action_id, None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the None needed?

@cathteng cathteng merged commit b6f80f8 into master Nov 25, 2025
66 checks passed
@cathteng cathteng deleted the cathy/aci/wags-conflict-remove-fire branch November 25, 2025 23:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Backend Automatically applied to PRs that change backend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants