Skip to content
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

IA-98: add rollout for sentry task latency #83244

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

bmckerry
Copy link
Member

In #71778 the option to allow latency metrics from a SentryTask was added, but defaulted to false and has since only been enabled on 3 tasks.

This PR adds a rollout option to increase the rate at which all tasks in a region report latency metrics. This will allow us to configure monitors based off of task latency instead of backlog similar to what we have for kafka.

@github-actions github-actions bot added the Scope: Backend Automatically applied to PRs that change backend components label Jan 10, 2025
Comment on lines -89 to -90
# Use a try/catch here to contain the blast radius of an exception being unhandled through the options lib
# Unhandled exception could cause all tasks to be effected and not work
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the code this comment refers to was deleted in a previous PR

do_record_timing_rollout = False
record_timing_rollout = options.get("sentry.tasks.record.timing.rollout")
if record_timing_rollout and record_timing_rollout > random():
do_record_timing_rollout = True
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setting record_timing = True here made it so the wrapped function wouldn't use the parameter record_timing, so I added do_record_timing_rollout for the rollout logic

Comment on lines 90 to 91
record_timing_rollout = options.get("sentry.tasks.record.timing.rollout")
if record_timing_rollout and record_timing_rollout > random():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use sentry.features.rollout.in_random_rollout to handle the comparison with random and handling unset option values.

Copy link

codecov bot commented Jan 10, 2025

❌ 4 Tests Failed:

Tests completed Failed Passed Skipped
23464 4 23460 272
View the top 3 failed tests by shortest run time
tests.sentry.tasks.test_base::test_task_silo_limit_call_control
Stack Traces | 0.039s run time
#x1B[1m#x1B[.../sentry/tasks/test_base.py#x1B[0m:32: in test_task_silo_limit_call_control
    assert "Control task hi" == control_task("hi")
#x1B[1m#x1B[.../sentry/silo/base.py#x1B[0m:158: in override
    return original_method(*args, **kwargs)
#x1B[1m#x1B[31m.venv/lib/python3.12.../site-packages/celery/local.py#x1B[0m:182: in __call__
    return self._get_current_object()(*a, **kw)
#x1B[1m#x1B[31m.venv/lib/python3.12.../celery/app/task.py#x1B[0m:411: in __call__
    return self.run(*args, **kwargs)
#x1B[1m#x1B[.../sentry/silo/base.py#x1B[0m:158: in override
    return original_method(*args, **kwargs)
#x1B[1m#x1B[.../sentry/tasks/base.py#x1B[0m:88: in _wrapped
    record_timing_rollout = in_random_rollout("sentry.tasks.record.timing.rollout")
#x1B[1m#x1B[.../sentry/features/rollout.py#x1B[0m:14: in in_random_rollout
    return random.random() < options.get(option_name)
#x1B[1m#x1B[.../sentry/options/manager.py#x1B[0m:299: in get
    result = self.store.get(opt, silent=silent)
#x1B[1m#x1B[.../sentry/options/store.py#x1B[0m:97: in get
    result = self.get_store(key, silent=silent)
#x1B[1m#x1B[.../sentry/options/store.py#x1B[0m:193: in get_store
    value = self.model.objects.get(key=key.name).value
#x1B[1m#x1B[31m.venv/lib/python3.12.../db/models/manager.py#x1B[0m:87: in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
#x1B[1m#x1B[31m.venv/lib/python3.12.../db/models/query.py#x1B[0m:645: in get
    num = len(clone)
#x1B[1m#x1B[31m.venv/lib/python3.12.../db/models/query.py#x1B[0m:382: in __len__
    self._fetch_all()
#x1B[1m#x1B[31m.venv/lib/python3.12.../db/models/query.py#x1B[0m:1928: in _fetch_all
    self._result_cache = list(self._iterable_class(self))
#x1B[1m#x1B[31m.venv/lib/python3.12.../db/models/query.py#x1B[0m:91: in __iter__
    results = compiler.execute_sql(
#x1B[1m#x1B[31m.venv/lib/python3.12.../models/sql/compiler.py#x1B[0m:1572: in execute_sql
    cursor = self.connection.cursor()
#x1B[1m#x1B[31m.venv/lib/python3.12.../django/utils/asyncio.py#x1B[0m:26: in inner
    return func(*args, **kwargs)
#x1B[1m#x1B[31m.venv/lib/python3.12.../backends/base/base.py#x1B[0m:320: in cursor
    return self._cursor()
#x1B[1m#x1B[.../db/postgres/decorators.py#x1B[0m:40: in inner
    return func(self, *args, **kwargs)
#x1B[1m#x1B[.../db/postgres/base.py#x1B[0m:108: in _cursor
    return super()._cursor()
#x1B[1m#x1B[31m.venv/lib/python3.12.../backends/base/base.py#x1B[0m:296: in _cursor
    self.ensure_connection()
#x1B[1m#x1B[31mE   RuntimeError: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.#x1B[0m
tests.sentry.tasks.test_base::test_task_silo_limit_call_monolith
Stack Traces | 0.039s run time
#x1B[1m#x1B[.../sentry/tasks/test_base.py#x1B[0m:37: in test_task_silo_limit_call_monolith
    assert "Region task hi" == region_task("hi")
#x1B[1m#x1B[.../sentry/silo/base.py#x1B[0m:158: in override
    return original_method(*args, **kwargs)
#x1B[1m#x1B[31m.venv/lib/python3.12.../site-packages/celery/local.py#x1B[0m:182: in __call__
    return self._get_current_object()(*a, **kw)
#x1B[1m#x1B[31m.venv/lib/python3.12.../celery/app/task.py#x1B[0m:411: in __call__
    return self.run(*args, **kwargs)
#x1B[1m#x1B[.../sentry/silo/base.py#x1B[0m:158: in override
    return original_method(*args, **kwargs)
#x1B[1m#x1B[.../sentry/tasks/base.py#x1B[0m:88: in _wrapped
    record_timing_rollout = in_random_rollout("sentry.tasks.record.timing.rollout")
#x1B[1m#x1B[.../sentry/features/rollout.py#x1B[0m:14: in in_random_rollout
    return random.random() < options.get(option_name)
#x1B[1m#x1B[.../sentry/options/manager.py#x1B[0m:299: in get
    result = self.store.get(opt, silent=silent)
#x1B[1m#x1B[.../sentry/options/store.py#x1B[0m:97: in get
    result = self.get_store(key, silent=silent)
#x1B[1m#x1B[.../sentry/options/store.py#x1B[0m:193: in get_store
    value = self.model.objects.get(key=key.name).value
#x1B[1m#x1B[31m.venv/lib/python3.12.../db/models/manager.py#x1B[0m:87: in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
#x1B[1m#x1B[31m.venv/lib/python3.12.../db/models/query.py#x1B[0m:645: in get
    num = len(clone)
#x1B[1m#x1B[31m.venv/lib/python3.12.../db/models/query.py#x1B[0m:382: in __len__
    self._fetch_all()
#x1B[1m#x1B[31m.venv/lib/python3.12.../db/models/query.py#x1B[0m:1928: in _fetch_all
    self._result_cache = list(self._iterable_class(self))
#x1B[1m#x1B[31m.venv/lib/python3.12.../db/models/query.py#x1B[0m:91: in __iter__
    results = compiler.execute_sql(
#x1B[1m#x1B[31m.venv/lib/python3.12.../models/sql/compiler.py#x1B[0m:1572: in execute_sql
    cursor = self.connection.cursor()
#x1B[1m#x1B[31m.venv/lib/python3.12.../django/utils/asyncio.py#x1B[0m:26: in inner
    return func(*args, **kwargs)
#x1B[1m#x1B[31m.venv/lib/python3.12.../backends/base/base.py#x1B[0m:320: in cursor
    return self._cursor()
#x1B[1m#x1B[.../db/postgres/decorators.py#x1B[0m:40: in inner
    return func(self, *args, **kwargs)
#x1B[1m#x1B[.../db/postgres/base.py#x1B[0m:108: in _cursor
    return super()._cursor()
#x1B[1m#x1B[31m.venv/lib/python3.12.../backends/base/base.py#x1B[0m:296: in _cursor
    self.ensure_connection()
#x1B[1m#x1B[31mE   RuntimeError: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.#x1B[0m
tests.sentry.tasks.test_base::test_task_silo_limit_call_region
Stack Traces | 0.041s run time
#x1B[1m#x1B[.../sentry/tasks/test_base.py#x1B[0m:20: in test_task_silo_limit_call_region
    result = region_task("hi")
#x1B[1m#x1B[.../sentry/silo/base.py#x1B[0m:158: in override
    return original_method(*args, **kwargs)
#x1B[1m#x1B[31m.venv/lib/python3.12.../site-packages/celery/local.py#x1B[0m:182: in __call__
    return self._get_current_object()(*a, **kw)
#x1B[1m#x1B[31m.venv/lib/python3.12.../celery/app/task.py#x1B[0m:411: in __call__
    return self.run(*args, **kwargs)
#x1B[1m#x1B[.../sentry/silo/base.py#x1B[0m:158: in override
    return original_method(*args, **kwargs)
#x1B[1m#x1B[.../sentry/tasks/base.py#x1B[0m:88: in _wrapped
    record_timing_rollout = in_random_rollout("sentry.tasks.record.timing.rollout")
#x1B[1m#x1B[.../sentry/features/rollout.py#x1B[0m:14: in in_random_rollout
    return random.random() < options.get(option_name)
#x1B[1m#x1B[.../sentry/options/manager.py#x1B[0m:299: in get
    result = self.store.get(opt, silent=silent)
#x1B[1m#x1B[.../sentry/options/store.py#x1B[0m:97: in get
    result = self.get_store(key, silent=silent)
#x1B[1m#x1B[.../sentry/options/store.py#x1B[0m:193: in get_store
    value = self.model.objects.get(key=key.name).value
#x1B[1m#x1B[31m.venv/lib/python3.12.../db/models/manager.py#x1B[0m:87: in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
#x1B[1m#x1B[31m.venv/lib/python3.12.../db/models/query.py#x1B[0m:645: in get
    num = len(clone)
#x1B[1m#x1B[31m.venv/lib/python3.12.../db/models/query.py#x1B[0m:382: in __len__
    self._fetch_all()
#x1B[1m#x1B[31m.venv/lib/python3.12.../db/models/query.py#x1B[0m:1928: in _fetch_all
    self._result_cache = list(self._iterable_class(self))
#x1B[1m#x1B[31m.venv/lib/python3.12.../db/models/query.py#x1B[0m:91: in __iter__
    results = compiler.execute_sql(
#x1B[1m#x1B[31m.venv/lib/python3.12.../models/sql/compiler.py#x1B[0m:1572: in execute_sql
    cursor = self.connection.cursor()
#x1B[1m#x1B[31m.venv/lib/python3.12.../django/utils/asyncio.py#x1B[0m:26: in inner
    return func(*args, **kwargs)
#x1B[1m#x1B[31m.venv/lib/python3.12.../backends/base/base.py#x1B[0m:320: in cursor
    return self._cursor()
#x1B[1m#x1B[.../db/postgres/decorators.py#x1B[0m:40: in inner
    return func(self, *args, **kwargs)
#x1B[1m#x1B[.../db/postgres/base.py#x1B[0m:108: in _cursor
    return super()._cursor()
#x1B[1m#x1B[31m.venv/lib/python3.12.../backends/base/base.py#x1B[0m:296: in _cursor
    self.ensure_connection()
#x1B[1m#x1B[31mE   RuntimeError: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.#x1B[0m

To view more test analytics, go to the Test Analytics Dashboard
📢 Thoughts on this report? Let us know!

Copy link
Member

@markstory markstory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

@getsantry
Copy link
Contributor

getsantry bot commented Feb 1, 2025

This pull request has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you add the label WIP, I will leave it alone unless WIP is removed ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

@getsantry getsantry bot added Stale and removed Stale labels Feb 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Scope: Backend Automatically applied to PRs that change backend components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants