Simple job queues for Python
This report summarizes scanner evidence for rq/rq, a Python project with 10,693 GitHub stars. SynthScan examined 35,153 lines of code across 143 source files, recording 694 pattern matches distributed across 15 syntactic categories. The legacy adjusted pattern signal is 22.9 (Elevated pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Can maintainers explain intent, assumptions, and trade-offs? 588 finding(s).
Are imports declared and package/API names verified? 67 finding(s).
Are wrappers, guards, and repeated structures necessary? 577 finding(s).
Which changes need focused human review? 694 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 694 distinct pattern matches across 15 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | tests/test_job.py | 131 | def test_create_job_from_string_function(self): | CODE |
| LOW⚡ | tests/test_job.py | 140 | def test_create_job_from_callable_class(self): | CODE |
| LOW⚡ | tests/test_job.py | 148 | def test_job_properties_set_data_property(self): | CODE |
| LOW⚡ | tests/test_job.py | 537 | def test_job_status_always_exists(self): | CODE |
| LOW⚡ | tests/test_job.py | 544 | def test_get_status_fails_when_job_deleted_from_redis(self): | CODE |
| LOW⚡ | tests/test_job.py | 553 | def test_job_access_outside_job_fails(self): | CODE |
| LOW⚡ | tests/test_job.py | 557 | def test_job_access_within_job_function(self): | CODE |
| LOW⚡ | tests/test_job.py | 566 | def test_job_access_within_synchronous_job_function(self): | CODE |
| LOW⚡ | tests/test_job.py | 570 | def test_job_async_status_finished(self): | CODE |
| LOW⚡ | tests/test_job.py | 576 | def test_enqueue_job_async_status_finished(self): | CODE |
| LOW⚡ | tests/test_job.py | 881 | def test_get_call_string_unicode(self): | CODE |
| LOW⚡ | tests/test_job.py | 889 | def test_create_job_from_static_method(self): | CODE |
| LOW⚡ | tests/test_job.py | 897 | def test_create_job_with_ttl_should_have_ttl_after_enqueued(self): | CODE |
| LOW⚡ | tests/test_job.py | 904 | def test_create_job_with_ttl_should_expire(self): | CODE |
| LOW⚡ | tests/test_job.py | 911 | def test_create_and_cancel_job(self): | CODE |
| LOW⚡ | tests/test_job.py | 948 | def test_create_and_cancel_job_with_serializer(self): | CODE |
| LOW⚡ | tests/test_job.py | 956 | def test_key_for_should_return_prefixed_job_id(self): | CODE |
| LOW⚡ | tests/test_job.py | 964 | def test_blocking_result_fetch(self): | CODE |
| LOW | tests/test_job.py | 110 | def test_create_instance_method_job(self): | CODE |
| LOW | tests/test_job.py | 120 | def test_create_job_with_serializer(self): | CODE |
| LOW | tests/test_job.py | 159 | def test_data_property_sets_job_properties(self): | CODE |
| LOW | tests/test_job.py | 236 | def test_persistence_of_empty_jobs(self): # noqa | CODE |
| LOW | tests/test_job.py | 242 | def test_persistence_of_typical_jobs(self): | CODE |
| LOW | tests/test_job.py | 276 | def test_persistence_of_parent_job(self): | CODE |
| LOW | tests/test_job.py | 307 | def test_persistence_of_callbacks(self): | CODE |
| LOW | tests/test_job.py | 360 | def test_fetching_unreadable_data(self): | CODE |
| LOW | tests/test_job.py | 391 | def test_compressed_exc_info_handling(self): | CODE |
| LOW | tests/test_job.py | 412 | def test_compressed_job_data_handling(self): | CODE |
| LOW | tests/test_job.py | 426 | def test_custom_meta_is_persisted(self): | CODE |
| LOW | tests/test_job.py | 454 | def test_custom_meta_is_rewriten_by_save_meta(self): | CODE |
| LOW | tests/test_job.py | 485 | def test_result_ttl_is_persisted(self): | CODE |
| LOW | tests/test_job.py | 497 | def test_failure_ttl_is_persisted(self): | CODE |
| LOW | tests/test_job.py | 509 | def test_description_is_persisted(self): | CODE |
| LOW | tests/test_job.py | 524 | def test_prepare_for_execution(self): | CODE |
| LOW | tests/test_job.py | 637 | def test_job_delete_removes_itself_from_registries(self): | CODE |
| LOW | tests/test_job.py | 730 | def test_job_delete_removes_results(self): | CODE |
| LOW | tests/test_job.py | 748 | def test_job_delete_results_with_pipeline(self): | CODE |
| LOW | tests/test_job.py | 763 | def test_job_delete_execution_registry(self): | CODE |
| LOW | tests/test_job.py | 786 | def test_create_job_with_invalid_id(self): | CODE |
| LOW | tests/test_job.py | 814 | def test_create_job_with_async(self): | CODE |
| LOW | tests/test_job.py | 829 | def test_coroutine_job_closes_event_loop(self): | CODE |
| LOW | tests/test_job.py | 841 | def test_coroutine_job_closes_event_loop_on_failure(self): | CODE |
| LOW | tests/test_job.py | 856 | def test_coroutine_job_closes_event_loop_on_cancellation(self): | CODE |
| LOW | tests/test_job.py | 869 | def test_coroutine_job_finalizes_async_resources(self): | CODE |
| LOW | tests/test_job.py | 926 | def test_create_and_cancel_job_fails_already_canceled(self): | CODE |
| LOW | tests/test_job.py | 980 | def test_should_enqueue_at_front(self): | CODE |
| LOW | tests/test_retry.py | 22 | def test_persistence_of_retry_data(self): | CODE |
| LOW | tests/test_retry.py | 137 | def test_job_create_with_retry(self): | CODE |
| LOW | tests/test_retry.py | 172 | def test_cleanup_handles_retries(self): | CODE |
| LOW | tests/test_retry.py | 265 | def test_handle_job_retry_max_retries_exceeded(self): | CODE |
| LOW | tests/test_retry.py | 327 | def test_job_handle_retry_with_interval_increments_number_of_retries(self): | CODE |
| LOW | tests/test_retry.py | 338 | def test_worker_handles_max_retry(self): | CODE |
| LOW | tests/test_retry.py | 365 | def test_worker_handles_retry_interval(self): | CODE |
| LOW | tests/test_retry.py | 398 | def test_worker_handles_max_retry_with_interval(self): | CODE |
| LOW | tests/test_retry.py | 416 | def test_worker_handles_enqueue_at_front_on_retry(self): | CODE |
| LOW | tests/test_retry.py | 430 | def test_worker_handles_enqueue_at_front_on_retry_with_interval(self): | CODE |
| LOW | tests/test_registry.py | 126 | def test_add_and_remove_with_serializer(self): | CODE |
| LOW | tests/test_registry.py | 202 | def test_clean_registries_with_serializer(self): | CODE |
| LOW | tests/test_registry.py | 255 | def test_jobs_are_put_in_registry(self): | CODE |
| LOW | tests/test_registry.py | 292 | def test_add_with_deferred_ttl(self): | CODE |
| 464 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | rq/queue.py | 155 | Returns a Queue instance, based on the naming conventions for naming the internal Redis keys. Can be used to re | STRING |
| HIGH | rq/queue.py | 577 | Creates a job based on parameters given Args: func (FunctionReferenceType): The function reference: | STRING |
| HIGH | rq/queue.py | 1178 | Puts job on ScheduledJobRegistry Args: job (Job): The job to schedule datetime (datetim | STRING |
| HIGH | rq/queue.py | 1233 | Enqueues a job for delayed execution checking dependencies. Args: job (Job): The job to enqueue | STRING |
| HIGH | rq/queue.py | 1657 | Helper method to abstract away from some Redis API details where LPOP accepts only a single key, whereas BLPOP | STRING |
| HIGH | rq/queue.py | 1733 | Class method returning the job_class instance at the front of the given set of Queues, where the order of the qu | STRING |
| HIGH | rq/registry.py | 198 | Requeues the job with the given job ID. Args: job_or_id (Union['Job', str]): The Job or the | STRING |
| HIGH | rq/registry.py | 684 | Returns datetime (UTC) at which job is scheduled to be enqueued Args: job_or_id (Union[Job, str]): | STRING |
| HIGH | rq/job.py | 270 | Creates a new Job instance for the given function, arguments, and keyword arguments. Args: | STRING |
| HIGH | rq/job.py | 415 | Gets the Job Status Args: refresh (bool, optional): Whether to refresh the Job. Defaults to True. | STRING |
| HIGH | rq/job.py | 1207 | Cancels the given job, which will prevent the job from ever being ran (or inspected). This method merel | STRING |
| HIGH | rq/utils.py | 80 | Resolve a function reference into instance and function name components. Args: func: The function reference | STRING |
| HIGH | rq/utils.py | 119 | Converts a bytes value to a string using `utf-8`. Args: v (Union[bytes, str]): The value (bytes or string) | STRING |
| HIGH | rq/utils.py | 167 | Returns an attribute from a dotted path name. Example: `path.to.func`. When the attribute we look for is a staticme | STRING |
| HIGH | rq/utils.py | 265 | Normalize configuration path to dotted module path format. Converts file paths like 'directory/config_file.py' or ' | STRING |
| HIGH | rq/utils.py | 308 | Validate that an absolute file path exists and points to a file. Args: file_path: The absolute file path to | STRING |
| HIGH | rq/scripts.py | 60 | Atomically check uniqueness, save job, and optionally push to queue using Lua script. Args: connection: Red | STRING |
| HIGH | rq/scripts.py | 166 | Atomically check uniqueness, save job, and add to scheduled registry using Lua script. Args: connection: Re | STRING |
| HIGH | rq/worker_registration.py | 59 | Returns a list of worker keys for a given queue. Args: queue (Optional['Queue'], optional): The Que | STRING |
| HIGH | rq/worker/base.py | 283 | Returns a Worker instance, based on the naming conventions for naming the internal Redis keys. Can be used to r | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/fixtures.py | 6 | CODE | |
| LOW | rq/queue.py | 1 | CODE | |
| LOW | rq/executions.py | 1 | CODE | |
| LOW | rq/cron_job_registry.py | 1 | CODE | |
| LOW | rq/worker_pool.py | 1 | CODE | |
| LOW | rq/command.py | 7 | CODE | |
| LOW | rq/command.py | 9 | CODE | |
| LOW | rq/results.py | 1 | CODE | |
| LOW | rq/webhook.py | 1 | CODE | |
| LOW | rq/maintenance.py | 8 | CODE | |
| LOW | rq/registry.py | 1 | CODE | |
| LOW | rq/cron.py | 1 | CODE | |
| LOW | rq/job.py | 1 | CODE | |
| LOW | rq/serializers.py | 1 | CODE | |
| LOW | rq/cron_scheduler_registry.py | 1 | CODE | |
| LOW | rq/__init__.py | 2 | CODE | |
| LOW | rq/__init__.py | 3 | CODE | |
| LOW | rq/__init__.py | 3 | CODE | |
| LOW | rq/__init__.py | 3 | CODE | |
| LOW | rq/__init__.py | 3 | CODE | |
| LOW | rq/__init__.py | 4 | CODE | |
| LOW | rq/__init__.py | 5 | CODE | |
| LOW | rq/__init__.py | 6 | CODE | |
| LOW | rq/__init__.py | 8 | CODE | |
| LOW | rq/__init__.py | 9 | CODE | |
| LOW | rq/__init__.py | 9 | CODE | |
| LOW | rq/__init__.py | 9 | CODE | |
| LOW | rq/suspension.py | 1 | CODE | |
| LOW | rq/types.py | 1 | CODE | |
| LOW | rq/types.py | 10 | CODE | |
| LOW | rq/types.py | 12 | CODE | |
| LOW | rq/types.py | 12 | CODE | |
| LOW | rq/logutils.py | 1 | CODE | |
| LOW | rq/intermediate_queue.py | 1 | CODE | |
| LOW | rq/repeat.py | 1 | CODE | |
| LOW | rq/utils.py | 8 | CODE | |
| LOW | rq/callbacks.py | 1 | CODE | |
| LOW | rq/rate_limit.py | 1 | CODE | |
| LOW | rq/group.py | 1 | CODE | |
| LOW | rq/scheduler.py | 1 | CODE | |
| LOW | rq/worker_registration.py | 1 | CODE | |
| LOW | rq/job_lifecycle.py | 1 | CODE | |
| LOW | rq/decorators.py | 1 | CODE | |
| LOW | rq/cli/__init__.py | 2 | CODE | |
| LOW | rq/cli/__init__.py | 6 | CODE | |
| LOW | rq/cli/__init__.py | 7 | CODE | |
| LOW | rq/cli/__init__.py | 8 | CODE | |
| LOW | rq/worker/__init__.py | 1 | CODE | |
| LOW | rq/worker/__init__.py | 2 | CODE | |
| LOW | rq/worker/__init__.py | 2 | CODE | |
| LOW | rq/worker/__init__.py | 2 | CODE | |
| LOW | rq/worker/__init__.py | 2 | CODE | |
| LOW | rq/worker/__init__.py | 2 | CODE | |
| LOW | rq/worker/__init__.py | 2 | CODE | |
| LOW | rq/worker/__init__.py | 10 | CODE | |
| LOW | rq/worker/__init__.py | 11 | CODE | |
| LOW | rq/worker/__init__.py | 11 | CODE | |
| LOW | rq/worker/__init__.py | 11 | CODE | |
| LOW | rq/worker/__init__.py | 11 | CODE | |
| LOW | rq/worker/__init__.py | 11 | CODE | |
| 3 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | tests/test_commands.py | 57 | except ResponseError: | CODE |
| HIGH | rq/queue.py | 399 | except AttributeError: | CODE |
| HIGH | rq/job.py | 1451 | except NoSuchJobError: | CODE |
| HIGH | rq/timeouts.py | 42 | except BaseTimeoutException: | CODE |
| HIGH | rq/worker/worker_classes.py | 27 | except ImportError: | CODE |
| HIGH | rq/worker/base.py | 24 | except ImportError: | CODE |
| HIGH | rq/worker/base.py | 1277 | except OSError: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | tests/test_worker.py | 1831 | except Exception: | CODE |
| LOW | rq/queue.py | 1617 | except Exception: | CODE |
| LOW | rq/queue.py | 1806 | except Exception as e: | CODE |
| LOW | rq/webhook.py | 99 | except Exception: | CODE |
| LOW | rq/registry.py | 307 | except Exception: | CODE |
| LOW | rq/registry.py | 621 | except Exception: | CODE |
| LOW | rq/cron.py | 487 | except Exception as e: | CODE |
| LOW | rq/cron.py | 509 | except Exception as e: | CODE |
| LOW | rq/cron.py | 523 | except Exception as e: | CODE |
| LOW | rq/job.py | 609 | except Exception as e: | CODE |
| LOW | rq/job.py | 999 | except Exception: | CODE |
| LOW | rq/job.py | 1031 | except Exception: | CODE |
| LOW | rq/job.py | 1044 | except Exception: # depends on the serializer | CODE |
| LOW | rq/job.py | 1297 | except Exception: | CODE |
| LOW | rq/callbacks.py | 57 | except Exception: | CODE |
| LOW | rq/callbacks.py | 74 | except Exception: | CODE |
| LOW | rq/cli/workers.py | 169 | except Exception as e: | CODE |
| LOW | rq/cli/helpers.py | 259 | except Exception: | CODE |
| LOW | rq/worker/worker_classes.py | 159 | except Exception: | CODE |
| LOW⚡ | rq/worker/base.py | 790 | except Exception: | CODE |
| LOW⚡ | rq/worker/base.py | 797 | except Exception: | CODE |
| LOW | rq/worker/base.py | 775 | except Exception: | CODE |
| LOW | rq/worker/base.py | 1436 | except Exception: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | rq/worker_pool.py | 0 | installs signal handlers for handling sigint and sigterm gracefully. | STRING |
| HIGH | rq/scheduler.py | 0 | installs signal handlers for handling sigint and sigterm gracefully. | STRING |
| HIGH | rq/worker/base.py | 0 | installs signal handlers for handling sigint and sigterm gracefully. | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | tests/test_repeat.py | 69 | # Create a job with repeat settings | COMMENT |
| MEDIUM | tests/test_results.py | 66 | # Create a result without any execution info (simulates pre-upgrade data). | COMMENT |
| MEDIUM | tests/test_cron.py | 256 | # Create a Cron instance first | COMMENT |
| MEDIUM | .github/workflows/valkey.yml | 27 | # Define the service container for Valkey | COMMENT |
| MEDIUM | rq/registry.py | 251 | """This method is automatically called by `count()` and `get_job_ids()` methods | STRING |
| MEDIUM | rq/worker/base.py | 1115 | """This method is called by the main `Worker` (not the horse) as it prepares for execution. | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | rq/queue.py | 664 | CODE | |
| LOW | rq/command.py | 104 | CODE | |
| LOW | rq/registry.py | 566 | CODE | |
| LOW | rq/cron.py | 206 | CODE | |
| LOW | rq/job.py | 1201 | CODE | |
| LOW | rq/job.py | 1338 | CODE | |
| LOW | rq/job.py | 1904 | CODE | |
| LOW | rq/repeat.py | 31 | CODE | |
| LOW | rq/utils.py | 79 | CODE | |
| LOW | rq/dependency.py | 11 | CODE | |
| LOW | rq/scheduler.py | 232 | CODE | |
| LOW | rq/cli/helpers.py | 267 | CODE | |
| LOW | rq/worker/base.py | 595 | CODE | |
| LOW | rq/worker/base.py | 827 | CODE | |
| LOW | rq/worker/base.py | 1129 | CODE | |
| LOW | rq/worker/base.py | 1464 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | rq/queue.py | 553 | CODE | |
| LOW | rq/queue.py | 723 | CODE | |
| LOW | rq/queue.py | 809 | CODE | |
| LOW | rq/worker_pool.py | 256 | CODE | |
| LOW | rq/results.py | 25 | CODE | |
| LOW | rq/results.py | 274 | CODE | |
| LOW | rq/cron.py | 676 | CODE | |
| LOW | rq/cron.py | 72 | CODE | |
| LOW | rq/cron.py | 325 | CODE | |
| LOW | rq/job.py | 245 | CODE | |
| LOW | rq/decorators.py | 21 | CODE | |
| LOW | rq/cli/helpers.py | 334 | CODE | |
| LOW | rq/worker/base.py | 134 | CODE | |
| LOW | rq/worker/base.py | 595 | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | rq/cron.py | 198 | def set_enqueue_time(self, time: datetime) -> None: | CODE |
| LOW | rq/job.py | 437 | def set_status(self, status: JobStatus, pipeline: Pipeline | None = None) -> None: | CODE |
| LOW | rq/__init__.py | 11 | __all__ = [ | CODE |
| LOW | rq/utils.py | 45 | logger = logging.getLogger(__name__) | CODE |
| LOW | rq/worker/__init__.py | 20 | __all__ = [ | CODE |
| LOW | rq/worker/base.py | 251 | def _set_ip_address(self, connection: Redis) -> None: | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | rq/local.py | 87 | >>> ls.push(42) | STRING |
| HIGH | rq/local.py | 90 | >>> ls.push(23) | STRING |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_cli.py | 991 | # Make the start method just return to avoid infinite loop | COMMENT |
| LOW | rq/local.py | 12 | # Since each thread has its own greenlet we can just use those as identifiers | COMMENT |
| LOW | rq/timeouts.py | 50 | # just pass through, BaseTimeoutException being handled normally to the | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/test_scheduler.py | 81 | job = Job.create('myfunc', connection=self.connection) | COMMENT |
| LOW | .github/workflows/codeql.yaml | 21 | - name: Initialize CodeQL | COMMENT |
| LOW | rq/worker_pool.py | 121 | self.handle_dead_worker(data) | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | tests/test_queue.py | 632 | pipe.watch(b'fake_key') # Test watch then enqueue | CODE |
| LOW⚡ | tests/test_queue.py | 639 | pipe.set(b'fake_key', b'fake_value') | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | rq/repeat.py | 106 | # Decrement repeats_left | COMMENT |
| LOW | rq/utils.py | 283 | # Check if it's already a dotted path (no path separators and no .py extension) | COMMENT |