#4616·bullmq

[Bug]: Python QueueEvents broken on Postgres

Author: Striar-YunisCreated Aug 24, 2026Updated Sep 15, 2026
Labelsbug

Version

vpy3.0.4

Platform

Python

What happened?

In the PythonSDK, QueueEvents ignores the backend being Postgres and constructs a Redis connection. It unconditionally constructs RedisConnection and passes the PostgreSQL DSN to redis.from_url().

QueueEvents should honor backend="postgres", construct the PostgreSQL event consumer, and emit the same generic and per-job lifecycle callbacks exposed for Redis. The PostgreSQL backend already includes an append-only event table, publish_event, cursor-based read_events, and a shared bullmq_events notification channel. QueueEvents appears to be the remaining public API that has not been routed through the backend abstraction.

How to reproduce.

Test Environment

bash
docker run -d --rm \
  --name bmq-postgres-test \
  -e POSTGRES_PASSWORD=postgres \
  -e POSTGRES_DB=postgres \
  -p 5432:5432 \
  postgres:16

python3 -m venv .venv
source .venv/bin/activate
pip install 'bullmq[postgres]==3.0.4'

DATABASE_URL='postgresql://postgres:[email protected]:5432/postgres' \
  python bullmq_postgres_queue_events_repro.py

bullmq_postgres_queue_events_repro.py

python
#!/usr/bin/env python3

"""Reproduce QueueEvents ignoring BullMQ's PostgreSQL backend selection."""

import asyncio
import os
from importlib.metadata import version

from bullmq import Queue, QueueEvents

QUEUE_NAME = "postgres-queue-events-repro"
POSTGRES_URL = os.environ.get(
    "DATABASE_URL",
    "postgresql://postgres:[email protected]:5432/postgres",
)

async def main() -> None:
    opts = {
        "backend": "postgres",
        "connection": POSTGRES_URL,
        "schema": "bullmq_queue_events_repro",
    }

    queue = Queue(QUEUE_NAME, opts)
    events = None
    try:
        print(f"bullmq={version('bullmq')}", flush=True)
        print(f"Queue backend={type(queue.backend).__name__}", flush=True)

        # This should select the PostgreSQL backend just as Queue does. In
        # BullMQ 3.0.4 it instead passes POSTGRES_URL to redis.from_url().
        events = QueueEvents(QUEUE_NAME, {**opts, "autorun": False})
        print("QueueEvents constructed successfully", flush=True)
    finally:
        if events is not None:
            await events.close()
        await queue.close()


if __name__ == "__main__":
    asyncio.run(main())

Relevant log output

bash
bullmq=3.0.4
Queue backend=PostgresBackend
Traceback (most recent call last):
  File "/home/ubuntu/Work/gitlab.com/bullmq_postgres_queue_events_repro.py", line 41, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.12/asyncio/runners.py", line 194, in run
    return runner.run(main)
           ^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/asyncio/runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3.12/asyncio/base_events.py", line 687, in run_until_complete
    return future.result()
           ^^^^^^^^^^^^^^^
  File "/home/ubuntu/Work/gitlab.com/bullmq_postgres_queue_events_repro.py", line 32, in main
    events = QueueEvents(QUEUE_NAME, {**opts, "autorun": False})
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/Work/gitlab.com/.venv/lib/python3.12/site-packages/bullmq/queue_events.py", line 81, in __init__
    self.redisConnection = RedisConnection(
                           ^^^^^^^^^^^^^^^^
  File "/home/ubuntu/Work/gitlab.com/.venv/lib/python3.12/site-packages/bullmq/redis_connection.py", line 109, in __init__
    self.conn = redis.from_url(redisOpts, decode_responses=True, retry=retry,
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/Work/gitlab.com/.venv/lib/python3.12/site-packages/redis/asyncio/utils.py", line 16, in from_url
    return Redis.from_url(url, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/Work/gitlab.com/.venv/lib/python3.12/site-packages/redis/asyncio/client.py", line 185, in from_url
    connection_pool = ConnectionPool.from_url(url, **kwargs)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/Work/gitlab.com/.venv/lib/python3.12/site-packages/redis/asyncio/connection.py", line 1292, in from_url
    url_options = parse_url(url)
                  ^^^^^^^^^^^^^^
  File "/home/ubuntu/Work/gitlab.com/.venv/lib/python3.12/site-packages/redis/asyncio/connection.py", line 1224, in parse_url
    raise ValueError(
ValueError: Redis URL must specify one of the following schemes (redis://, rediss://, unix://)

Code of Conduct

  • I agree to follow this project's Code of Conduct