Skip to content

feat(uptime): Implement detector handler #91107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/sentry/uptime/consumers/results_consumer.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,17 @@
send_uptime_config_deletion,
update_remote_uptime_subscription,
)
from sentry.uptime.types import IncidentStatus, ProjectUptimeSubscriptionMode
from sentry.uptime.types import (
DATA_SOURCE_UPTIME_SUBSCRIPTION,
IncidentStatus,
ProjectUptimeSubscriptionMode,
)
from sentry.utils import metrics
from sentry.utils.arroyo_producer import SingletonProducer
from sentry.utils.kafka_config import get_kafka_producer_cluster_options, get_topic_definition
from sentry.workflow_engine.models.data_source import DataPacket
from sentry.workflow_engine.models.detector import Detector
from sentry.workflow_engine.processors.data_packet import process_data_packets

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -295,6 +301,12 @@ def handle_active_result(
result: CheckResult,
metric_tags: dict[str, str],
):
if features.has("organizations:uptime-detector-handler", detector.project.organization):
process_data_packets(
[DataPacket[CheckResult](source_id=result["subscription_id"], packet=result)],
DATA_SOURCE_UPTIME_SUBSCRIPTION,
)

uptime_status = uptime_subscription.uptime_status
result_status = result["status"]

Expand Down
53 changes: 53 additions & 0 deletions src/sentry/uptime/consumers/workflow_engine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from typing import Any, override

from sentry_kafka_schemas.schema_types.uptime_results_v1 import CheckResult, CheckStatus

from sentry.types.group import PriorityLevel
from sentry.uptime.models import get_uptime_subscription
from sentry.workflow_engine.handlers.detector.base import DetectorOccurrence
from sentry.workflow_engine.handlers.detector.stateful import StatefulGroupingDetectorHandler
from sentry.workflow_engine.models.data_source import DataPacket
from sentry.workflow_engine.types import DetectorGroupKey, DetectorPriorityLevel


class UptimeDetectorHandler(StatefulGroupingDetectorHandler[CheckResult, CheckStatus]):
@override
def get_dedupe_value(self, data_packet: DataPacket[CheckResult]) -> int:
return int(data_packet.packet["scheduled_check_time_ms"])

@override
def get_group_key_values(
self,
data_packet: DataPacket[CheckResult],
) -> dict[DetectorGroupKey, CheckStatus]:
return {None: data_packet.packet["status"]}

@override
@property
def priority_transition_thresholds(self) -> dict[DetectorPriorityLevel, int]:
"""
Require 3 uptime checks to fail before activating the detector.
Likewise require 3 successful checks to recover.
"""
return {
DetectorPriorityLevel.OK: 3,
DetectorPriorityLevel.HIGH: 3,
}

@override
def build_fingerprint(self, group_key) -> list[str]:
# TODO: Use `build_detector_fingerprint_component` from
# https://github.com/getsentry/sentry/pull/91087. This needs to match
# the fingerprints we're using for the old issues.
return "TODO"

@override
def build_occurrence_and_event_data(
self, group_key: DetectorGroupKey, new_status: PriorityLevel
) -> tuple[DetectorOccurrence, dict[str, Any]]:
uptime_subscription = get_uptime_subscription(self.detector)
# TODO: We need the datapacket here to pull things out, we should
# either try and re-use some of the build_occurrence_from_result or
# just copy paste here

return (DetectorOccurrence(), {})
2 changes: 2 additions & 0 deletions src/sentry/uptime/grouptype.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from sentry.issues.grouptype import GroupCategory, GroupType
from sentry.ratelimits.sliding_windows import Quota
from sentry.types.group import PriorityLevel
from sentry.uptime.consumers.workflow_engine import UptimeDetectorHandler
from sentry.uptime.types import ProjectUptimeSubscriptionMode
from sentry.workflow_engine.types import DetectorSettings

Expand All @@ -21,6 +22,7 @@ class UptimeDomainCheckFailure(GroupType):
enable_auto_resolve = False
enable_escalation_detection = False
detector_settings = DetectorSettings(
handler=UptimeDetectorHandler,
config_schema={
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "A representation of an uptime alert",
Expand Down
9 changes: 9 additions & 0 deletions src/sentry/uptime/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,15 @@ def get_detector(uptime_subscription: UptimeSubscription) -> Detector | None:
return None


def get_uptime_subscription(detector: Detector) -> ProjectUptimeSubscription:
"""
Given a detector get the matching uptime subscription
"""
data_source = detector.data_sources.first()
assert data_source
return UptimeSubscription.objects.get_from_cache(id=int(data_source.source_id))


def get_project_subscription(detector: Detector) -> ProjectUptimeSubscription:
"""
Given a detector get the matching project subscription
Expand Down
Loading