Skip to content

feat(outcomes): Route billing referrers to daily outcomes table#7877

Draft
dashed wants to merge 2 commits intomasterfrom
feat/billing-daily-table-routing
Draft

feat(outcomes): Route billing referrers to daily outcomes table#7877
dashed wants to merge 2 commits intomasterfrom
feat/billing-daily-table-routing

Conversation

@dashed
Copy link
Copy Markdown
Member

@dashed dashed commented Apr 15, 2026

Summary

Add hybrid routing to OutcomesStorageSelector so queries are directed to the correct outcomes table based on both time-range and referrer:

  1. OutcomesQuerySettings — honours the explicit use_daily flag (unchanged).
  2. Time-range — if the query's lower timestamp bound is older than 90 days, route to the daily table because the hourly table does not retain data that far back.
  3. Referrer — if the referrer starts with "billing.", route to daily (billing queries need 13-month retention only available in the daily table, triggered by sentry's UsageService).
  4. Default — hourly.

The time-range check uses get_time_range() to extract the query's timestamp lower bound and compares it against a 90-day threshold. This ensures queries that reach beyond hourly retention are automatically served from the daily table, regardless of referrer.

Test plan

  • Existing OutcomesQuerySettings test cases pass (use_daily flag routing unchanged)
  • No-timestamp + billing referrer → daily
  • No-timestamp + non-billing referrer → hourly
  • Timestamp >90 days ago + non-billing referrer → daily (time-range routing)
  • Timestamp >90 days ago + billing referrer → daily (both triggers)
  • Timestamp <90 days ago + billing referrer → daily (referrer fallback)
  • Timestamp <90 days ago + non-billing referrer → hourly (default)
  • Pre-commit checks pass (ruff format, ruff lint)

outcomes_key = (
self.daily_storage if query_settings.get_use_daily() else self.hourly_storage
)
elif hasattr(query_settings, "referrer") and query_settings.referrer.startswith("billing."):
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 query AST has the time range in it, it would be better to inspect that and route to the daily storage if it's greater than 90d

@dashed dashed force-pushed the feat/billing-daily-table-routing branch from de21b4b to 93b513a Compare April 15, 2026 21:19
dashed added 2 commits April 15, 2026 17:29
…retention

Queries whose lower timestamp bound is older than 90 days are now
routed to the outcomes_daily table instead of outcomes_hourly. The
hourly table only retains ~90 days of data, so older queries would
return incomplete results.

Uses get_time_range() to extract the lower timestamp bound from the
query AST. TimeSeriesProcessor runs before storage selection in the
entity pipeline, so datetime Literals are available for inspection.

Existing behavior is preserved:
- OutcomesQuerySettings(use_daily=True) still routes to daily
- OutcomesQuerySettings(use_daily=False) still routes to hourly
- Queries within the 90-day window still route to hourly
Billing queries need 13-month retention available only in the daily
table. Even when the query's time range is within the 90-day hourly
window, billing queries should route to daily for consistent results
across the full billing history.

Add a referrer-based fallback: queries with a referrer starting with
"billing." are routed to the daily table. This is triggered by
sentry's UsageService which uses referrer
"billing.usage_service.clickhouse".

Routing priority:
1. OutcomesQuerySettings — explicit use_daily flag
2. Time-range — lower timestamp bound older than 90 days
3. Referrer — starts with "billing."
4. Default — hourly
@dashed dashed force-pushed the feat/billing-daily-table-routing branch from 93b513a to a67cf2c Compare April 15, 2026 21:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants