ProvenPin Install

Dramatiq actors run inline with StubBroker and results middleware: working versions (tested 2026-10-15)

Define Dramatiq actors that store results, run them synchronously against a StubBroker with a background Worker, and assert on results, failures and async actors offline.

passed5 passed · 0 failed2026-10-15 15:58 UTC
Status
passed
Last passed
2026-10-15 15:58 UTC
Tests
5 / 5
Language
Python
Runtime
Python 3.13.16
pinned versions3
dramatiq@2.2.1pytest@9.1.1pytest-asyncio@1.4.0
run it
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt
.venv/bin/python -m pytest -q
test environment
Python 3.13.16
linux 6.17.0-1022-azure
x64
runner: github-actions 38764699834

The code

Exactly the files that passed. Your agent can pull them with get_recipe("dramatiq-stub-broker-testing") (install), or see them on GitHub.

requirements.txt
dramatiq==2.2.1
pytest==9.1.1
pytest-asyncio==1.4.0
tasks.py
import asyncio

import dramatiq
from dramatiq.brokers.stub import StubBroker
from dramatiq.middleware.asyncio import AsyncIO
from dramatiq.results import Results
from dramatiq.results.backends.stub import StubBackend

broker = StubBroker()
broker.add_middleware(AsyncIO())
broker.add_middleware(Results(backend=StubBackend()))
dramatiq.set_broker(broker)


@dramatiq.actor(store_results=True)
def add(x, y):
    return x + y


@dramatiq.actor
def square(x):
    return x * x


@dramatiq.actor(store_results=True, max_retries=0)
def divide(x, y):
    return x / y


@dramatiq.actor(store_results=True)
async def upper(text):
    await asyncio.sleep(0)
    return text.upper()
tests/test_tasks.py
import asyncio

import pytest
from dramatiq.results.errors import ResultFailure, ResultMissing
from dramatiq.worker import Worker

from tasks import add, broker, divide, square, upper


@pytest.fixture
def worker():
    w = Worker(broker, worker_timeout=100, worker_threads=1)
    w.start()
    yield w
    w.stop()
    broker.dead_letters_by_queue.clear()


def test_actor_runs_on_worker(worker):
    message = add.send(2, 3)
    broker.join(add.queue_name)
    assert message.get_result(backend=broker.get_results_backend()) == 5


def test_result_missing_without_store_results(worker):
    message = square.send(4)
    broker.join(square.queue_name)
    with pytest.raises(ResultMissing):
        message.get_result(backend=broker.get_results_backend())


def test_join_fail_fast_reraises_actor_error(worker):
    divide.send(1, 0)
    with pytest.raises(ZeroDivisionError):
        broker.join(divide.queue_name, fail_fast=True)


def test_result_failure_after_non_fail_fast_join(worker):
    message = divide.send(1, 0)
    broker.join(divide.queue_name, fail_fast=False)
    with pytest.raises(ResultFailure) as exc:
        message.get_result(backend=broker.get_results_backend(), block=True)
    assert "ZeroDivisionError" in str(exc.value)


async def test_async_actor_result_is_retrieved_from_a_thread(worker):
    message = upper.send("abc")
    await asyncio.to_thread(broker.join, upper.queue_name)
    result = await asyncio.to_thread(message.get_result, backend=broker.get_results_backend(), block=True)
    assert result == "ABC"
pytest.ini
[pytest]
pythonpath = .
asyncio_mode = auto

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.