Delete legacy.py (#2083)

* Delete legacy.py

* Deleted Sentry's built in integration.

* Fixed ruff warnings.
This commit is contained in:
Selwin Ong 2024-05-02 08:20:41 +07:00 committed by GitHub
parent 87af9b51e9
commit 4c28ec617a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 5 additions and 169 deletions

View File

@ -34,4 +34,4 @@ jobs:
- name: Lint with ruff - name: Lint with ruff
run: | run: |
# stop the build if there are Python syntax errors. # stop the build if there are Python syntax errors.
ruff check --show-source rq tests ruff check --output-format=full rq tests

View File

@ -1,49 +1,8 @@
--- ---
title: "RQ: Sending exceptions to Sentry" title: "RQ: Sending Exceptions to Sentry"
layout: patterns layout: patterns
--- ---
## Sending Exceptions to Sentry ## Sending Exceptions to Sentry
[Sentry](https://www.getsentry.com/) is a popular exception gathering service. Please visit Sentry's [RQ integration page](https://docs.sentry.io/platforms/python/integrations/rq/).
RQ allows you to very easily send job exceptions to Sentry. To do this, you'll
need to have [sentry-sdk](https://pypi.org/project/sentry-sdk/) installed.
There are a few ways to start sending job exceptions to Sentry.
### Configuring Sentry Through CLI
Simply invoke the `rqworker` script using the ``--sentry-dsn`` argument.
```console
rq worker --sentry-dsn https://my-dsn@sentry.io/123
```
### Configuring Sentry Through a Config File
Declare `SENTRY_DSN` in RQ's config file like this:
```python
SENTRY_DSN = 'https://my-dsn@sentry.io/123'
```
And run RQ's worker with your config file:
```console
rq worker -c my_settings
```
Visit [this page](https://python-rq.org/docs/workers/#using-a-config-file)
to read more about running RQ using a config file.
### Configuring Sentry Through Environment Variable
Simple set `RQ_SENTRY_DSN` in your environment variable and RQ will
automatically start Sentry integration for you.
```console
RQ_SENTRY_DSN="https://my-dsn@sentry.io/123" rq worker
```

View File

@ -85,7 +85,6 @@ dependencies = [
"pytest", "pytest",
"pytest-cov", "pytest-cov",
"ruff", "ruff",
"sentry-sdk<2",
"tox", "tox",
] ]
[tool.hatch.envs.test.scripts] [tool.hatch.envs.test.scripts]
@ -99,7 +98,7 @@ skip-string-normalization = true
[tool.ruff] [tool.ruff]
# Set what ruff should check for. # Set what ruff should check for.
# See https://beta.ruff.rs/docs/rules/ for a list of rules. # See https://beta.ruff.rs/docs/rules/ for a list of rules.
select = [ lint.select = [
"E", # pycodestyle errors "E", # pycodestyle errors
"F", # pyflakes errors "F", # pyflakes errors
"I", # import sorting "I", # import sorting
@ -108,7 +107,7 @@ select = [
line-length = 120 # To match black. line-length = 120 # To match black.
target-version = "py38" target-version = "py38"
[tool.ruff.isort] [tool.ruff.lint.isort]
known-first-party = ["rq"] known-first-party = ["rq"]
section-order = ["future", "standard-library", "third-party", "first-party", "local-folder"] section-order = ["future", "standard-library", "third-party", "first-party", "local-folder"]

View File

@ -182,9 +182,6 @@ def info(cli_config, interval, raw, only_queues, only_workers, by_queue, queues,
@click.option('--disable-job-desc-logging', is_flag=True, help='Turn off description logging.') @click.option('--disable-job-desc-logging', is_flag=True, help='Turn off description logging.')
@click.option('--verbose', '-v', is_flag=True, help='Show more output') @click.option('--verbose', '-v', is_flag=True, help='Show more output')
@click.option('--quiet', '-q', is_flag=True, help='Show less output') @click.option('--quiet', '-q', is_flag=True, help='Show less output')
@click.option('--sentry-ca-certs', envvar='RQ_SENTRY_CA_CERTS', help='Path to CRT file for Sentry DSN')
@click.option('--sentry-debug', envvar='RQ_SENTRY_DEBUG', help='Enable debug')
@click.option('--sentry-dsn', envvar='RQ_SENTRY_DSN', help='Report exceptions to this Sentry DSN')
@click.option('--exception-handler', help='Exception handler(s) to use', multiple=True) @click.option('--exception-handler', help='Exception handler(s) to use', multiple=True)
@click.option('--pid', help='Write the process ID number to a file at the specified path') @click.option('--pid', help='Write the process ID number to a file at the specified path')
@click.option('--disable-default-exception-handler', '-d', is_flag=True, help='Disable RQ\'s default exception handler') @click.option('--disable-default-exception-handler', '-d', is_flag=True, help='Disable RQ\'s default exception handler')
@ -209,9 +206,6 @@ def worker(
disable_job_desc_logging, disable_job_desc_logging,
verbose, verbose,
quiet, quiet,
sentry_ca_certs,
sentry_debug,
sentry_dsn,
exception_handler, exception_handler,
pid, pid,
disable_default_exception_handler, disable_default_exception_handler,
@ -229,9 +223,6 @@ def worker(
settings = read_config_file(cli_config.config) if cli_config.config else {} settings = read_config_file(cli_config.config) if cli_config.config else {}
# Worker specific default arguments # Worker specific default arguments
queues = queues or settings.get('QUEUES', ['default']) queues = queues or settings.get('QUEUES', ['default'])
sentry_ca_certs = sentry_ca_certs or settings.get('SENTRY_CA_CERTS')
sentry_debug = sentry_debug or settings.get('SENTRY_DEBUG')
sentry_dsn = sentry_dsn or settings.get('SENTRY_DSN')
name = name or settings.get('NAME') name = name or settings.get('NAME')
dict_config = settings.get('DICT_CONFIG') dict_config = settings.get('DICT_CONFIG')
@ -288,13 +279,6 @@ def worker(
serializer=serializer, serializer=serializer,
) )
# Should we configure Sentry?
if sentry_dsn:
sentry_opts = {"ca_certs": sentry_ca_certs, "debug": sentry_debug}
from rq.contrib.sentry import register_sentry
register_sentry(sentry_dsn, **sentry_opts)
# if --verbose or --quiet, override --logging_level # if --verbose or --quiet, override --logging_level
if verbose or quiet: if verbose or quiet:
logging_level = None logging_level = None
@ -445,9 +429,6 @@ def enqueue(
@main.command() @main.command()
@click.option('--burst', '-b', is_flag=True, help='Run in burst mode (quit after all work is done)') @click.option('--burst', '-b', is_flag=True, help='Run in burst mode (quit after all work is done)')
@click.option('--logging-level', '-l', type=str, default="INFO", help='Set logging level') @click.option('--logging-level', '-l', type=str, default="INFO", help='Set logging level')
@click.option('--sentry-ca-certs', envvar='RQ_SENTRY_CA_CERTS', help='Path to CRT file for Sentry DSN')
@click.option('--sentry-debug', envvar='RQ_SENTRY_DEBUG', help='Enable debug')
@click.option('--sentry-dsn', envvar='RQ_SENTRY_DSN', help='Report exceptions to this Sentry DSN')
@click.option('--verbose', '-v', is_flag=True, help='Show more output') @click.option('--verbose', '-v', is_flag=True, help='Show more output')
@click.option('--quiet', '-q', is_flag=True, help='Show less output') @click.option('--quiet', '-q', is_flag=True, help='Show less output')
@click.option('--log-format', type=str, default=DEFAULT_LOGGING_FORMAT, help='Set the format of the logs') @click.option('--log-format', type=str, default=DEFAULT_LOGGING_FORMAT, help='Set the format of the logs')
@ -462,9 +443,6 @@ def worker_pool(
logging_level, logging_level,
queues, queues,
serializer, serializer,
sentry_ca_certs,
sentry_debug,
sentry_dsn,
verbose, verbose,
quiet, quiet,
log_format, log_format,
@ -478,9 +456,6 @@ def worker_pool(
settings = read_config_file(cli_config.config) if cli_config.config else {} settings = read_config_file(cli_config.config) if cli_config.config else {}
# Worker specific default arguments # Worker specific default arguments
queue_names: List[str] = queues or settings.get('QUEUES', ['default']) queue_names: List[str] = queues or settings.get('QUEUES', ['default'])
sentry_ca_certs = sentry_ca_certs or settings.get('SENTRY_CA_CERTS')
sentry_debug = sentry_debug or settings.get('SENTRY_DEBUG')
sentry_dsn = sentry_dsn or settings.get('SENTRY_DSN')
setup_loghandlers_from_args(verbose, quiet, date_format, log_format) setup_loghandlers_from_args(verbose, quiet, date_format, log_format)
@ -513,13 +488,6 @@ def worker_pool(
) )
pool.start(burst=burst, logging_level=logging_level) pool.start(burst=burst, logging_level=logging_level)
# Should we configure Sentry?
if sentry_dsn:
sentry_opts = {"ca_certs": sentry_ca_certs, "debug": sentry_debug}
from rq.contrib.sentry import register_sentry
register_sentry(sentry_dsn, **sentry_opts)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -1,23 +0,0 @@
import logging
from rq import Worker, get_current_connection
logger = logging.getLogger(__name__)
def cleanup_ghosts(conn=None, worker_class=Worker):
"""
RQ versions < 0.3.6 suffered from a race condition where workers, when
abruptly terminated, did not have a chance to clean up their worker
registration, leading to reports of ghosted workers in `rqinfo`. Since
0.3.6, new worker registrations automatically expire, and the worker will
make sure to refresh the registrations as long as it's alive.
This function will clean up any of such legacy ghosted workers.
"""
conn = conn if conn else get_current_connection()
for worker in worker_class.all(connection=conn):
if conn.ttl(worker.key) == -1:
ttl = worker.worker_ttl
conn.expire(worker.key, ttl)
logger.info('Marked ghosted worker {0} to expire in {1} seconds.'.format(worker.name, ttl))

View File

@ -1,8 +0,0 @@
def register_sentry(sentry_dsn, **opts):
"""Given a Raven client and an RQ worker, registers exception handlers
with the worker so exceptions are logged to Sentry.
"""
import sentry_sdk
from sentry_sdk.integrations.rq import RqIntegration
sentry_sdk.init(sentry_dsn, integrations=[RqIntegration()], **opts)

View File

@ -1,5 +1,4 @@
import warnings import warnings
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from .intermediate_queue import IntermediateQueue from .intermediate_queue import IntermediateQueue

View File

@ -1,2 +0,0 @@
REDIS_HOST = "testhost.example.com"
SENTRY_DSN = 'https://123@sentry.io/123'

View File

@ -1,54 +0,0 @@
from unittest import mock
from click.testing import CliRunner
from rq import Queue
from rq.cli import main
from rq.cli.helpers import read_config_file
from rq.contrib.sentry import register_sentry
from rq.worker import SimpleWorker
from tests import RQTestCase
from tests.fixtures import div_by_zero
class FakeSentry:
servers = []
def captureException(self, *args, **kwds): # noqa
pass # we cannot check this, because worker forks
class TestSentry(RQTestCase):
def setUp(self):
super().setUp()
db_num = self.connection.connection_pool.connection_kwargs['db']
self.redis_url = 'redis://127.0.0.1:6379/%d' % db_num
def test_reading_dsn_from_file(self):
settings = read_config_file('tests.config_files.sentry')
self.assertIn('SENTRY_DSN', settings)
self.assertEqual(settings['SENTRY_DSN'], 'https://123@sentry.io/123')
@mock.patch('rq.contrib.sentry.register_sentry')
def test_cli_flag(self, mocked):
"""rq worker -u <url> -b --exception-handler <handler>"""
# connection = Redis.from_url(self.redis_url)
runner = CliRunner()
runner.invoke(main, ['worker', '-u', self.redis_url, '-b', '--sentry-dsn', 'https://1@sentry.io/1'])
self.assertEqual(mocked.call_count, 1)
runner.invoke(main, ['worker-pool', '-u', self.redis_url, '-b', '--sentry-dsn', 'https://1@sentry.io/1'])
self.assertEqual(mocked.call_count, 2)
def test_failure_capture(self):
"""Test failure is captured by Sentry SDK"""
from sentry_sdk import Hub
hub = Hub.current
self.assertIsNone(hub.last_event_id())
queue = Queue(connection=self.connection)
queue.enqueue(div_by_zero)
worker = SimpleWorker(queues=[queue], connection=self.connection)
register_sentry('https://123@sentry.io/123')
worker.work(burst=True)
self.assertIsNotNone(hub.last_event_id())

View File

@ -8,7 +8,6 @@ deps=
psutil psutil
pytest pytest
pytest-cov pytest-cov
sentry-sdk
passenv= passenv=
RUN_SSL_TESTS RUN_SSL_TESTS
@ -51,7 +50,6 @@ skipdist = True
basepython = python3.10 basepython = python3.10
deps= deps=
pytest pytest
sentry-sdk
psutil psutil
passenv= passenv=
RUN_SSL_TESTS RUN_SSL_TESTS