diff --git a/src/sentry/api/endpoints/organization_events_timeseries.py b/src/sentry/api/endpoints/organization_events_timeseries.py index b7b8bd3f7a8a50..f1a71b427df188 100644 --- a/src/sentry/api/endpoints/organization_events_timeseries.py +++ b/src/sentry/api/endpoints/organization_events_timeseries.py @@ -15,6 +15,8 @@ from sentry.api.endpoints.organization_events_stats import SENTRY_BACKEND_REFERRERS from sentry.api.endpoints.timeseries import ( EMPTY_STATS_RESPONSE, + INGESTION_DELAY, + INGESTION_DELAY_MESSAGE, Row, SeriesMeta, StatsMeta, @@ -24,6 +26,7 @@ from sentry.api.utils import handle_query_errors from sentry.constants import MAX_TOP_EVENTS from sentry.models.organization import Organization +from sentry.ratelimits.config import RateLimitConfig from sentry.search.eap.trace_metrics.config import ( TraceMetricsSearchResolverConfig, get_trace_metric_from_request, @@ -45,6 +48,7 @@ from sentry.snuba.spans_rpc import Spans from sentry.snuba.trace_metrics import TraceMetrics from sentry.snuba.utils import DATASET_LABELS, RPC_DATASETS +from sentry.types.ratelimit import RateLimit, RateLimitCategory from sentry.utils.snuba import SnubaTSResult TOP_EVENTS_DATASETS = { @@ -60,10 +64,6 @@ transactions, } -# Assumed ingestion delay for timeseries, this is a static number for now just to match how the frontend was doing it -INGESTION_DELAY = 90 -INGESTION_DELAY_MESSAGE = "INCOMPLETE_BUCKET" - def null_zero(value: float) -> float | None: if value == 0: @@ -78,6 +78,18 @@ class OrganizationEventsTimeseriesEndpoint(OrganizationEventsEndpointBase): "GET": ApiPublishStatus.EXPERIMENTAL, } + enforce_rate_limit = True + + rate_limits = RateLimitConfig( + limit_overrides={ + "GET": { + RateLimitCategory.IP: RateLimit(limit=30, window=1, concurrent_limit=15), + RateLimitCategory.USER: RateLimit(limit=30, window=1, concurrent_limit=15), + RateLimitCategory.ORGANIZATION: RateLimit(limit=30, window=1, concurrent_limit=15), + } + } + ) + def get_features( self, organization: Organization, request: Request ) -> Mapping[str, bool | None]: diff --git a/src/sentry/api/endpoints/timeseries.py b/src/sentry/api/endpoints/timeseries.py index 4ae2e2221a44ec..190ffd93ea83bb 100644 --- a/src/sentry/api/endpoints/timeseries.py +++ b/src/sentry/api/endpoints/timeseries.py @@ -1,5 +1,9 @@ from typing import Any, Literal, NotRequired, TypedDict +# Assumed ingestion delay for timeseries, this is a static number for now just to match how the frontend was doing it +INGESTION_DELAY = 90 +INGESTION_DELAY_MESSAGE = "INCOMPLETE_BUCKET" + class StatsMeta(TypedDict): dataset: str diff --git a/tests/snuba/api/endpoints/test_organization_events_timeseries.py b/tests/snuba/api/endpoints/test_organization_events_timeseries.py index aaab4bb36243bf..10d635c8d1f0c4 100644 --- a/tests/snuba/api/endpoints/test_organization_events_timeseries.py +++ b/tests/snuba/api/endpoints/test_organization_events_timeseries.py @@ -5,7 +5,7 @@ import pytest from django.urls import reverse -from sentry.api.endpoints.organization_events_timeseries import INGESTION_DELAY_MESSAGE +from sentry.api.endpoints.timeseries import INGESTION_DELAY_MESSAGE from sentry.testutils.cases import APITestCase, SnubaTestCase from sentry.testutils.helpers.datetime import before_now, freeze_time from sentry.utils.samples import load_data