Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
code cleanup
Browse files Browse the repository at this point in the history
JoshFerge committed Jan 28, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 7dc15cf commit f9df369
Showing 3 changed files with 54 additions and 63 deletions.
26 changes: 26 additions & 0 deletions src/sentry/testutils/cases.py
Original file line number Diff line number Diff line change
@@ -2339,6 +2339,32 @@ def store_uptime_check(self, uptime_check):
)
assert response.status_code == 200

def store_snuba_uptime_check(self, subscription_id: str | None, check_status: str):
scheduled_time = datetime.now() - timedelta(minutes=5)
timestamp = scheduled_time + timedelta(seconds=1)
http_status = 200 if check_status == "success" else random.choice([408, 500, 502, 503, 504])

self.store_uptime_check(
{
"organization_id": self.organization.id,
"project_id": self.project.id,
"retention_days": 30,
"region": f"region_{random.randint(1, 3)}",
"environment": "production",
"subscription_id": subscription_id,
"guid": str(uuid.uuid4()),
"scheduled_check_time_ms": int(scheduled_time.timestamp() * 1000),
"actual_check_time_ms": int(timestamp.timestamp() * 1000),
"duration_ms": random.randint(1, 1000),
"status": check_status,
"status_reason": None,
"trace_id": str(uuid.uuid4()),
"request_info": {
"status_code": http_status,
},
}
)


# AcceptanceTestCase and TestCase are mutually exclusive base classses
class ReplaysAcceptanceTestCase(AcceptanceTestCase, SnubaTestCase):
50 changes: 21 additions & 29 deletions src/sentry/uptime/endpoints/organization_uptime_stats.py
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@
from sentry.api.bases.organization import OrganizationEndpoint, OrganizationPermission
from sentry.models.organization import Organization
from sentry.models.project import Project
from sentry.uptime.models import ProjectUptimeSubscription, UptimeSubscription
from sentry.uptime.models import ProjectUptimeSubscription
from sentry.utils.snuba_rpc import timeseries_rpc

logger = logging.getLogger(__name__)
@@ -32,7 +32,7 @@


@region_silo_endpoint
@extend_schema(tags=["Crons"])
@extend_schema(tags=["Uptime Monitors"])
class OrganizationUptimeStatsEndpoint(OrganizationEndpoint, StatsMixin):
publish_status = {
"GET": ApiPublishStatus.EXPERIMENTAL,
@@ -61,30 +61,27 @@ def get(self, request: Request, organization: Organization) -> Response:
return self.respond("Invalid uptime subscription ids provided", status=400)

try:
responses = self._make_eap_request(
eap_response = self._make_eap_request(
organization, projects, uptime_subscription_ids, timerange_args
)
except Exception:
logger.exception("Error making EAP RPC request for uptime check stats")
return self.respond("error making request", status=400)

formatted_response = self._format_response(responses)
formatted_response = self._format_response(eap_response)

return self.respond(formatted_response)

def _authorize_uptime_subscription_ids(
self, uptime_subscription_ids: list[str], projects: list[Project]
) -> None:
project_subscriptions = ProjectUptimeSubscription.objects.filter(
project_id__in=[project.id for project in projects],
).values_list("uptime_subscription_id", flat=True)

subscriptions = UptimeSubscription.objects.filter(
id__in=project_subscriptions,
subscription_id__in=uptime_subscription_ids,
).values_list("subscription_id", flat=True)
valid_subscription_ids = ProjectUptimeSubscription.objects.filter(
project_id__in=[project.id for project in projects],
uptime_subscription__subscription_id__in=uptime_subscription_ids,
).values_list("uptime_subscription__subscription_id", flat=True)

if set(uptime_subscription_ids) != set(subscriptions):
if set(uptime_subscription_ids) != set(valid_subscription_ids):
raise ValueError("Invalid uptime subscription ids provided")

def _make_eap_request(
@@ -93,7 +90,7 @@ def _make_eap_request(
projects: list[Project],
uptime_subscription_ids: list[str],
timerange_args: StatsArgsDict,
) -> list[TimeSeriesResponse]:
) -> TimeSeriesResponse:
start_timestamp = Timestamp()
start_timestamp.FromDatetime(timerange_args["start"])
end_timestamp = Timestamp()
@@ -139,33 +136,28 @@ def _make_eap_request(
),
)
responses = timeseries_rpc([request])
return responses
assert len(responses) == 1
return responses[0]

def _format_response(
self, responses: list[TimeSeriesResponse]
self, response: TimeSeriesResponse
) -> dict[str, list[tuple[int, dict[str, float]]]]:
"""
Formats the response from the EAP RPC request into a dictionary of subscription ids to a list of tuples
of timestamps and a dictionary of check statuses to counts.
"""
formatted_data: dict[str, dict[int, dict[str, float]]] = {}

for response in responses:
for timeseries in response.result_timeseries:
subscription_id = timeseries.group_by_attributes["uptime_subscription_id"]
status = timeseries.group_by_attributes["check_status"]

if subscription_id not in formatted_data:
formatted_data[subscription_id] = defaultdict(
lambda: {"failure": 0.0, "success": 0.0}
)

for bucket, data_point in zip(timeseries.buckets, timeseries.data_points):
unix_ts = int(bucket.seconds)
for timeseries in response.result_timeseries:
subscription_id = timeseries.group_by_attributes["uptime_subscription_id"]
status = timeseries.group_by_attributes["check_status"]

value = data_point.data if data_point.data_present else 0.0
if subscription_id not in formatted_data:
formatted_data[subscription_id] = defaultdict(lambda: {"failure": 0, "success": 0})

formatted_data[subscription_id][unix_ts][status] = value
for bucket, data_point in zip(timeseries.buckets, timeseries.data_points):
value = data_point.data if data_point.data_present else 0
formatted_data[subscription_id][bucket.seconds][status] = int(value)

final_data: dict[str, list[tuple[int, dict[str, float]]]] = {}
for subscription_id, timestamps in formatted_data.items():
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import random
import uuid
from datetime import datetime, timedelta, timezone

@@ -16,32 +15,6 @@ class OrganizationUptimeCheckIndexEndpointTest(
):
endpoint = "sentry-api-0-organization-uptime-stats"

def store_snuba_uptime_check(self, subscription_id: str | None, check_status: str):
scheduled_time = datetime.now(timezone.utc) - timedelta(minutes=5)
timestamp = scheduled_time + timedelta(seconds=1)
http_status = 200 if check_status == "success" else random.choice([408, 500, 502, 503, 504])

self.store_uptime_check(
{
"organization_id": self.organization.id,
"project_id": self.project.id,
"retention_days": 30,
"region": f"region_{random.randint(1, 3)}",
"environment": "production",
"subscription_id": subscription_id,
"guid": str(uuid.uuid4()),
"scheduled_check_time_ms": int(scheduled_time.timestamp() * 1000),
"actual_check_time_ms": int(timestamp.timestamp() * 1000),
"duration_ms": random.randint(1, 1000),
"status": check_status,
"status_reason": None,
"trace_id": str(uuid.uuid4()),
"request_info": {
"status_code": http_status,
},
}
)

def setUp(self):
super().setUp()
self.login_as(user=self.user)
@@ -73,13 +46,13 @@ def test_simple(self):
data = json.loads(json.dumps(response.data))
assert data == {
self.subscription_id: [
[1736881458, {"failure": 0.0, "success": 0.0}],
[1736967858, {"failure": 0.0, "success": 0.0}],
[1737054258, {"failure": 0.0, "success": 0.0}],
[1737140658, {"failure": 0.0, "success": 0.0}],
[1737227058, {"failure": 0.0, "success": 0.0}],
[1737313458, {"failure": 0.0, "success": 0.0}],
[1737399858, {"failure": 3.0, "success": 3.0}],
[1736881458, {"failure": 0, "success": 0}],
[1736967858, {"failure": 0, "success": 0}],
[1737054258, {"failure": 0, "success": 0}],
[1737140658, {"failure": 0, "success": 0}],
[1737227058, {"failure": 0, "success": 0}],
[1737313458, {"failure": 0, "success": 0}],
[1737399858, {"failure": 3, "success": 3}],
]
}

0 comments on commit f9df369

Please sign in to comment.