mirror of https://github.com/rq/rq.git
Delete legacy.py (#2083)
* Delete legacy.py * Deleted Sentry's built in integration. * Fixed ruff warnings.
This commit is contained in:
parent
87af9b51e9
commit
4c28ec617a
|
@ -34,4 +34,4 @@ jobs:
|
|||
- name: Lint with ruff
|
||||
run: |
|
||||
# stop the build if there are Python syntax errors.
|
||||
ruff check --show-source rq tests
|
||||
ruff check --output-format=full rq tests
|
||||
|
|
|
@ -1,49 +1,8 @@
|
|||
---
|
||||
title: "RQ: Sending exceptions to Sentry"
|
||||
title: "RQ: Sending Exceptions to Sentry"
|
||||
layout: patterns
|
||||
---
|
||||
|
||||
## Sending Exceptions to Sentry
|
||||
|
||||
[Sentry](https://www.getsentry.com/) is a popular exception gathering service.
|
||||
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
|
||||
```
|
||||
Please visit Sentry's [RQ integration page](https://docs.sentry.io/platforms/python/integrations/rq/).
|
|
@ -85,7 +85,6 @@ dependencies = [
|
|||
"pytest",
|
||||
"pytest-cov",
|
||||
"ruff",
|
||||
"sentry-sdk<2",
|
||||
"tox",
|
||||
]
|
||||
[tool.hatch.envs.test.scripts]
|
||||
|
@ -99,7 +98,7 @@ skip-string-normalization = true
|
|||
[tool.ruff]
|
||||
# Set what ruff should check for.
|
||||
# See https://beta.ruff.rs/docs/rules/ for a list of rules.
|
||||
select = [
|
||||
lint.select = [
|
||||
"E", # pycodestyle errors
|
||||
"F", # pyflakes errors
|
||||
"I", # import sorting
|
||||
|
@ -108,7 +107,7 @@ select = [
|
|||
line-length = 120 # To match black.
|
||||
target-version = "py38"
|
||||
|
||||
[tool.ruff.isort]
|
||||
[tool.ruff.lint.isort]
|
||||
known-first-party = ["rq"]
|
||||
section-order = ["future", "standard-library", "third-party", "first-party", "local-folder"]
|
||||
|
||||
|
|
|
@ -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('--verbose', '-v', is_flag=True, help='Show more 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('--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')
|
||||
|
@ -209,9 +206,6 @@ def worker(
|
|||
disable_job_desc_logging,
|
||||
verbose,
|
||||
quiet,
|
||||
sentry_ca_certs,
|
||||
sentry_debug,
|
||||
sentry_dsn,
|
||||
exception_handler,
|
||||
pid,
|
||||
disable_default_exception_handler,
|
||||
|
@ -229,9 +223,6 @@ def worker(
|
|||
settings = read_config_file(cli_config.config) if cli_config.config else {}
|
||||
# Worker specific default arguments
|
||||
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')
|
||||
dict_config = settings.get('DICT_CONFIG')
|
||||
|
||||
|
@ -288,13 +279,6 @@ def worker(
|
|||
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:
|
||||
logging_level = None
|
||||
|
@ -445,9 +429,6 @@ def enqueue(
|
|||
@main.command()
|
||||
@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('--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('--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')
|
||||
|
@ -462,9 +443,6 @@ def worker_pool(
|
|||
logging_level,
|
||||
queues,
|
||||
serializer,
|
||||
sentry_ca_certs,
|
||||
sentry_debug,
|
||||
sentry_dsn,
|
||||
verbose,
|
||||
quiet,
|
||||
log_format,
|
||||
|
@ -478,9 +456,6 @@ def worker_pool(
|
|||
settings = read_config_file(cli_config.config) if cli_config.config else {}
|
||||
# Worker specific default arguments
|
||||
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)
|
||||
|
||||
|
@ -513,13 +488,6 @@ def worker_pool(
|
|||
)
|
||||
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__':
|
||||
main()
|
||||
|
|
|
@ -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))
|
|
@ -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)
|
|
@ -1,5 +1,4 @@
|
|||
import warnings
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from .intermediate_queue import IntermediateQueue
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
REDIS_HOST = "testhost.example.com"
|
||||
SENTRY_DSN = 'https://123@sentry.io/123'
|
|
@ -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())
|
Loading…
Reference in New Issue