Skip to content

fix(hybridcloud): Allow skip-on-failure for Bitbucket and GHE webhooks - #121057

Draft
vaind wants to merge 1 commit into
masterfrom
fix/webhook-skip-on-failure-bitbucket-ghe
Draft

fix(hybridcloud): Allow skip-on-failure for Bitbucket and GHE webhooks#121057
vaind wants to merge 1 commit into
masterfrom
fix/webhook-skip-on-failure-bitbucket-ghe

Conversation

@vaind

@vaind vaind commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Draining a webhook mailbox aborts on the first delivery failure unless the payload's provider is in hybridcloud.webhookpayload.skip_on_failure_providers (deliver_webhooks.py:287, :563). Only github was listed, so a single wedged message blocks everything behind it for up to MAX_DELIVERY_AGE (3 days) — Bitbucket Server mailboxes have been seen holding tens of undelivered payloads for days behind one failing head. This adds github_enterprise, bitbucket and bitbucket_server.

Why these three are safe

  • github_enterpriseGithubEnterpriseRequestParser overrides only provider (parsers/github_enterprise.py:20-21) and runs literal subclasses of GitHub's handlers (github_enterprise/webhook.py:144-183). The allowlist is an exact string match, so GHE never matched "github" — an unintended exclusion, not a risk decision.
  • bitbucket / bitbucket_server — one push-only handler each (bitbucket/webhook.py:170, bitbucket_server/webhook.py:160), commits inserted idempotently under except IntegrityError: pass (:148-160, :134-148), per-organization mailboxes. Bitbucket Server re-fetches each self-contained fromHash..toHash range from the API (:101-116). No create/update/delete lifecycle to reorder.

Known caveat

Both Bitbucket handlers call update_repo_data (bitbucket/webhook.py:83-108, bitbucket_server/webhook.py:44-51), a last-writer-wins refresh of the stored repo name and URL from the event body. A push carrying a pre-rename name, retried after a later push, can briefly write the stale name back. It self-heals on the next successful push and renames are rare — assessed as not disqualifying, but it is the one place reordering is observable for these providers.

Why GitLab is not in this list

IssuesEventWebhook._handle_status_change (gitlab/webhooks.py:325-349) passes a delta, {"action": action}, into sync_status_inbound rather than a state snapshot, and get_resolve_sync_action (gitlab/issue_sync.py:262-277) maps it straight through — CLOSE → RESOLVE, REOPEN → UNRESOLVE — without re-reading the issue. A reordered CLOSE/REOPEN pair leaves the Sentry group resolved while the GitLab issue is open. vsts, jira_server and msteams are order-dependent for similar reasons. jira is also not cleared, for a different reason: its verdict was UNCLEAR because sync_status_inbound dispatches via apply_async (mixins/issues.py:485), so mailbox ordering is already void before the handler runs.

No production effect on its own

The registered default only governs environments without an explicit override, and sentry-options-automator pins this fleet-wide. getsentry/sentry-options-automator#9018 is the change that actually takes effect in prod; merging this one alone changes nothing on sentry.io.

Draft until the in-flight PR adding monotonic guards to the GitHub and GitLab pull-request lifecycle writes lands — merge this after it.

A mailbox drain aborts on the first delivery failure unless the payload's provider is
in `hybridcloud.webhookpayload.skip_on_failure_providers`, so a single wedged message
blocks everything behind it for up to MAX_DELIVERY_AGE. Bitbucket Server mailboxes have
been observed stuck for days behind one failing head payload.

Add the three providers whose cell-side handlers tolerate reordering:

- github_enterprise: GithubEnterpriseRequestParser subclasses GithubRequestParser and
  only overrides `provider`, so GHE runs literal subclasses of GitHub's webhook handlers
  yet never matched the exact-string allowlist. An unintended exclusion, not a decision.
- bitbucket / bitbucket_server: each endpoint registers a single push handler (repo:push
  and repo:refs_changed) and inserts commits idempotently under `except IntegrityError:
  pass`. Bitbucket Server re-fetches each self-contained fromHash..toHash range from the
  API. Neither has a create/update/delete lifecycle that reordering could corrupt.

Deliberately excluded: gitlab, vsts, jira_server and msteams are order-dependent.
jira was not assessed and remains a follow-up.

The registered default only governs environments without an explicit override; the
production value lives in sentry-options-automator.
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.

1 participant