Skip to content

feat(ingest-metrics): Ensure billing metrics consumer avoids outcome double-billing#117186

Merged
klochek merged 4 commits into
masterfrom
christopherklochek/billing_consumer_relay
Jun 16, 2026
Merged

feat(ingest-metrics): Ensure billing metrics consumer avoids outcome double-billing#117186
klochek merged 4 commits into
masterfrom
christopherklochek/billing_consumer_relay

Conversation

@klochek

@klochek klochek commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

With relay producing billing outcomes here, introduce and check for a new tag ("billing_outcome_accepted") to avoid double-billing.

I checked for prior string existence with:

SELECT string, count(*) 
FROM sentry_{perf,}stringindexer 
WHERE 1=1
    AND string IN (
        'billing_outcome_accepted'
    ) 
GROUP BY string;

Guarded by a new temporary flag organizations:relay-generate-billing-outcome

@klochek klochek requested review from a team as code owners June 9, 2026 15:47
@github-actions github-actions Bot added the Scope: Backend Automatically applied to PRs that change backend components label Jun 9, 2026
Comment thread src/sentry/ingest/billing_metrics_consumer.py

manager.add("projects:workflow-engine-performance-detectors", ProjectFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=False)

manager.add("organizations:relay-generate-billing-outcome", OrganizationFeature, FeatureHandlerStrategy.FLAGPOLE, api_expose=False)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The feature flag also needs to be exposed to Relay, search for EXPOSABLE_FEATURES

Comment thread src/sentry/ingest/billing_metrics_consumer.py
assert next_step.join.call_count == 1


@with_feature("organizations:relay-generate-billing-outcome")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
@with_feature("organizations:relay-generate-billing-outcome")

Mentioning the feature here should not be necessary because the consumer-side behavior is determined by the tag, not the feature flag, right? This might also be what confused sentry[bot] in their comment above.

"has_transaction": PREFIX + 281,
"was_transaction": PREFIX + 282,
"is_segment": PREFIX + 283,
"billing_outcome_accepted": PREFIX + 284,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not sure if you already bikeshedded on the name but billing_outcome_emitted would make slightly more sense to me (the outcome is Accepted but the thing relay does is emitting it).

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 978bfdc. Configure here.

Comment thread src/sentry/features/temporary.py

span_metric_id = SPAN_METRICS_NAMES["c:spans/usage@none"]
span_is_segment_tag = str(SHARED_TAG_STRINGS["is_segment"])
billing_outcome_accepted_tag = str(SHARED_TAG_STRINGS["billing_outcome_emitted"])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Bug: The variable billing_outcome_accepted_tag is misleadingly named, as it references the string "billing_outcome_emitted". If the external service sends "billing_outcome_accepted", the double-billing prevention will fail.
Severity: CRITICAL

Suggested Fix

Verify the exact tag name sent by the corresponding Relay change. If Relay sends "billing_outcome_accepted", update the string registered in src/sentry/sentry_metrics/indexer/strings.py to match. If Relay sends "billing_outcome_emitted", rename the variable billing_outcome_accepted_tag to billing_outcome_emitted_tag for clarity.

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/ingest/billing_metrics_consumer.py#L45

Potential issue: A new mechanism to prevent double-billing for span metrics relies on a
tag check. The variable `billing_outcome_accepted_tag` is used for this check, but it is
assigned the string value `"billing_outcome_emitted"`. The pull request description and
the variable's name imply that the tag sent by the external service (Relay) is
`"billing_outcome_accepted"`. If Relay sends a tag with this name, the consumer's check
for `"billing_outcome_emitted"` will not find it. This would cause the double-billing
prevention logic to silently fail for all metrics, defeating the purpose of the change.

Also affects:

  • src/sentry/sentry_metrics/indexer/strings.py:206~206

@klochek klochek merged commit 992069d into master Jun 16, 2026
85 checks passed
@klochek klochek deleted the christopherklochek/billing_consumer_relay branch June 16, 2026 17:09
sehr-m pushed a commit that referenced this pull request Jun 23, 2026
…double-billing (#117186)

With relay producing billing outcomes
[here](getsentry/relay#6066), introduce and
check for a new tag ("billing_outcome_accepted") to avoid
double-billing.

I checked for prior string existence with:

```
SELECT string, count(*) 
FROM sentry_{perf,}stringindexer 
WHERE 1=1
    AND string IN (
        'billing_outcome_accepted'
    ) 
GROUP BY string;
```

Guarded by a new temporary flag
`organizations:relay-generate-billing-outcome`
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