Skip to content

potential improvements to the class #54035

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

Merged
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
120 changes: 62 additions & 58 deletions src/sentry/integrations/request_buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

from django.conf import settings

from sentry.utils import json, redis
from sentry.utils import redis

BUFFER_SIZE = 30 # 30 days
KEY_EXPIRY = 60 * 60 * 24 * 30 # 30 days

IS_BROKEN_RANGE = 7 # 7 days
BROKEN_RANGE_DAYS = 7 # 7 days

VALID_KEYS = ["success", "error", "fatal"]


class IntegrationRequestBuffer:
Expand All @@ -17,93 +19,95 @@ class IntegrationRequestBuffer:
"""

def __init__(self, key):
self.integrationkey = key
self.integration_key = key

cluster_id = settings.SENTRY_INTEGRATION_ERROR_LOG_REDIS_CLUSTER
self.client = redis.redis_clusters.get(cluster_id)

def _convert_obj_to_dict(self, redis_object):
"""
Convert the request string stored in Redis to a python dict
"""
return json.loads(redis_object)

def _get_all_from_buffer(self):
"""
Get the list at the buffer key.
"""

ret = []
now = datetime.now()
i = 0
buffer_key = f"{self.integrationkey}:{now.strftime('%Y-%m-%d')}"
while self.client.hgetall(buffer_key):
ret.append(self.client.hgetall(buffer_key))
cur = (now - timedelta(days=i)).strftime("%Y-%m-%d")
buffer_key = f"{self.integrationkey}:{cur}"
i += 1

return ret

def _get_broken_range_from_buffer(self):
"""
Get the list at the buffer key in the broken range.
"""
def record_error(self):
self._add("error")

ret = []
now = datetime.now()
for i in range(IS_BROKEN_RANGE):
cur = (now - timedelta(days=i)).strftime("%Y-%m-%d")
buffer_key = f"{self.integrationkey}:{cur}"
ret.append(self.client.hgetall(buffer_key))
def record_success(self):
self._add("success")

return ret
def record_fatal(self):
self._add("fatal")

def is_integration_broken(self):
"""
Integration is broken if we have 7 consecutive days of errors and no successes OR have a fatal error

"""
items = self._get_broken_range_from_buffer()
broken_range_days_counts = self._get_broken_range_from_buffer()

data = [item for item in items if int(item.get("fatal_count", 0)) > 0]
days_fatal = []
days_error = []

if len(data) > 0:
return True
for day_count in broken_range_days_counts:
if int(day_count.get("fatal_count", 0)) > 0:
days_fatal.append(day_count)
elif (
int(day_count.get("error_count", 0)) > 0
and int(day_count.get("success_count", 0)) == 0
):
days_error.append(day_count)

data = [
item
for item in items
if int(item.get("error_count", 0)) > 0 and int(item.get("success_count", 0)) == 0
]
if len(days_fatal) > 0:
return True

if not len(data):
if not len(days_error):
return False

if len(data) < IS_BROKEN_RANGE:
if len(days_error) < BROKEN_RANGE_DAYS:
return False

return True

def add(self, count: str):
VALID_KEYS = ["success", "error", "fatal"]
def _add(self, count: str):
if count not in VALID_KEYS:
raise Exception("Requires a valid key param.")

now = datetime.now().strftime("%Y-%m-%d")
buffer_key = f"{self.integration_key}:{now}"

buffer_key = f"{self.integrationkey}:{now}"
pipe = self.client.pipeline()
pipe.hincrby(buffer_key, count + "_count", 1)
pipe.expire(buffer_key, KEY_EXPIRY)
pipe.execute()
pipe.reset()

def record_error(self):
self.add("error")
def _get_all_from_buffer(self):
"""
Get the list at the buffer key.
"""

def record_success(self):
self.add("success")
now = datetime.now()
all_range = [
f"{self.integration_key}:{(now - timedelta(days=i)).strftime('%Y-%m-%d')}"
for i in range(BUFFER_SIZE)
]

def record_fatal(self):
self.add("fatal")
return self._get_range_buffers(all_range)

def _get_broken_range_from_buffer(self):
"""
Get the list at the buffer key in the broken range.
"""

now = datetime.now()
broken_range_keys = [
f"{self.integration_key}:{(now - timedelta(days=i)).strftime('%Y-%m-%d')}"
for i in range(BROKEN_RANGE_DAYS)
]

return self._get_range_buffers(broken_range_keys)

def _get_range_buffers(self, keys):
pipe = self.client.pipeline()
ret = []
for key in keys:
pipe.hgetall(key)
response = pipe.execute()
for item in response:
ret.append(item)

return ret