Skip to content

Commit 57b306c

Browse files
authored
Add FastStream STOMP broker (#99)
1 parent 607823e commit 57b306c

File tree

26 files changed

+1057
-70
lines changed

26 files changed

+1057
-70
lines changed

.github/workflows/test.yml

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,3 @@ jobs:
4949
cache-dependency-glob: "**/pyproject.toml"
5050
- run: uv python install ${{ matrix.python-version }}
5151
- run: just install test -vv
52-
53-
test-integration:
54-
runs-on: ubuntu-latest
55-
strategy:
56-
fail-fast: false
57-
matrix:
58-
python-version:
59-
- "3.11"
60-
- "3.12"
61-
- "3.13"
62-
steps:
63-
- uses: actions/checkout@v4
64-
- uses: extractions/setup-just@v2
65-
- run: just test-integration
66-
env:
67-
PYTHON_IMAGE: python:${{ matrix.python-version }}-slim-bullseye

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ COPY packages/faststream-stomp/faststream_stomp/__init__.py packages/faststream-
1717

1818
ENV SETUPTOOLS_SCM_PRETEND_VERSION=0
1919
RUN --mount=type=cache,target=~/.cache/uv \
20-
ls packages/faststream-stomp && uv lock && uv sync
20+
uv lock && uv sync --all-extras --all-packages --frozen
2121
COPY . .

Justfile

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
default: install lint check-types test test-integration
1+
default: install lint check-types test
22

33
install:
44
uv lock --upgrade
@@ -11,13 +11,16 @@ lint:
1111
check-types:
1212
uv run mypy .
1313

14-
test *args:
15-
uv run pytest {{args}}
14+
test-fast *args:
15+
uv run pytest \
16+
--ignore=packages/stompman/test_stompman/test_integration.py \
17+
--ignore=packages/faststream-stomp/test_faststream_stomp/test_integration.py {{args}}
1618

17-
test-integration *args:
19+
test *args:
1820
#!/bin/bash
1921
trap 'echo; docker compose down --remove-orphans' EXIT
20-
docker compose run --build --rm app .venv/bin/pytest packages/stompman/test_stompman/integration.py --no-cov {{args}}
22+
docker compose up -d
23+
uv run pytest {{args}}
2124

2225
run-artemis:
2326
#!/bin/bash

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ Also, I want to pointed out that:
130130
- stompman is tested and used with [ActiveMQ Artemis](https://activemq.apache.org/components/artemis/) and [ActiveMQ Classic](https://activemq.apache.org/components/classic/).
131131
- Specification says that headers in CONNECT and CONNECTED frames shouldn't be escaped for backwards compatibility. stompman escapes headers in CONNECT frame (outcoming), but does not unescape headers in CONNECTED (outcoming).
132132

133+
### FastStream STOMP broker
134+
135+
[An implementation of STOMP broker for FastStream.](packages/faststream-stomp/README.md)
136+
133137
### Examples
134138

135-
See producer and consumer examples in [examples/](examples).
139+
See examples in [examples/](examples).

conftest.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from typing import cast
2+
3+
import pytest
4+
import stompman
5+
6+
7+
@pytest.fixture(
8+
params=[
9+
pytest.param(("asyncio", {"use_uvloop": True}), id="asyncio+uvloop"),
10+
pytest.param(("asyncio", {"use_uvloop": False}), id="asyncio"),
11+
],
12+
)
13+
def anyio_backend(request: pytest.FixtureRequest) -> object:
14+
return request.param
15+
16+
17+
@pytest.fixture(
18+
params=[
19+
stompman.ConnectionParameters(host="127.0.0.1", port=9000, login="admin", passcode=":=123"),
20+
stompman.ConnectionParameters(host="127.0.0.1", port=9001, login="admin", passcode=":=123"),
21+
]
22+
)
23+
def connection_parameters(request: pytest.FixtureRequest) -> stompman.ConnectionParameters:
24+
return cast("stompman.ConnectionParameters", request.param)

docker-compose.yml

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,16 @@
11
services:
2-
app:
3-
build:
4-
context: .
5-
args:
6-
PYTHON_IMAGE: ${PYTHON_IMAGE:-python:3.13-slim-bullseye}
7-
depends_on:
8-
activemq-artemis:
9-
condition: service_started
10-
activemq-classic:
11-
condition: service_started
12-
132
activemq-artemis:
143
image: apache/activemq-artemis:2.37.0-alpine
154
environment:
165
ARTEMIS_USER: admin
176
ARTEMIS_PASSWORD: ":=123"
187
ports:
19-
- 8161:8161
20-
- 61616:61616
8+
- 9000:61616
219

2210
activemq-classic:
2311
image: apache/activemq-classic:6.1.2
2412
environment:
2513
ACTIVEMQ_CONNECTION_USER: admin
2614
ACTIVEMQ_CONNECTION_PASSWORD: ":=123"
15+
ports:
16+
- 9001:61613

examples/consumer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import stompman
44

5-
server = stompman.ConnectionParameters(host="0.0.0.0", port=61616, login="admin", passcode=":=123") # noqa: S104
5+
server = stompman.ConnectionParameters(host="127.0.0.1", port=9000, login="admin", passcode=":=123")
66

77

88
async def handle_message(message_frame: stompman.MessageFrame) -> None:

examples/faststream_broadcast.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import asyncio
2+
3+
import faststream
4+
import faststream_stomp
5+
import stompman
6+
7+
server = stompman.ConnectionParameters(host="127.0.0.1", port=9000, login="admin", passcode=":=123")
8+
broker = faststream_stomp.StompBroker(stompman.Client([server]))
9+
10+
11+
@broker.subscriber("first")
12+
@broker.publisher("second")
13+
def _(message: str) -> str:
14+
print(message) # noqa: T201
15+
return "Hi from first handler!"
16+
17+
18+
@broker.subscriber("second")
19+
def _(message: str) -> None:
20+
print(message) # noqa: T201
21+
22+
23+
app = faststream.FastStream(broker)
24+
25+
26+
@app.after_startup
27+
async def send_first_message() -> None:
28+
await broker.connect()
29+
await broker.publish("Hi from startup!", "first")
30+
31+
32+
if __name__ == "__main__":
33+
asyncio.run(app.run())

examples/producer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import stompman
44

5-
server = stompman.ConnectionParameters(host="0.0.0.0", port=61616, login="admin", passcode=":=123") # noqa: S104
5+
server = stompman.ConnectionParameters(host="127.0.0.1", port=9000, login="admin", passcode=":=123")
66

77

88
async def main() -> None:

packages/faststream-stomp/README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,50 @@
11
# FastStream STOMP broker
22

3+
## How To Use
4+
5+
Install the package:
6+
7+
```sh
8+
uv add faststream-stomp
9+
poetry add faststream-stomp
10+
```
11+
12+
Basic usage:
13+
14+
```python
15+
import asyncio
16+
17+
import faststream
18+
import faststream_stomp
19+
import stompman
20+
21+
server = stompman.ConnectionParameters(host="127.0.0.1", port=61616, login="admin", passcode="password")
22+
broker = faststream_stomp.StompBroker(stompman.Client([server]))
23+
24+
25+
@broker.subscriber("first")
26+
@broker.publisher("second")
27+
def _(message: str) -> str:
28+
print(message) # this will print message from startup
29+
return "Hi from first handler!"
30+
31+
32+
@broker.subscriber("second")
33+
def _(message: str) -> None:
34+
print(message) # this will print message from first handler
35+
36+
37+
app = faststream.FastStream(broker)
38+
39+
40+
@app.after_startup
41+
async def send_first_message() -> None:
42+
await broker.connect()
43+
await broker.publish("Hi from startup!", "first")
44+
45+
46+
if __name__ == "__main__":
47+
asyncio.run(app.run())
48+
```
49+
50+
Also there are `StompRouter` and `TestStompBroker` for testing. It works similarly to built-in brokers from FastStream, I recommend to read the original [FastStream documentation](https://faststream.airt.ai/latest/getting-started).

0 commit comments

Comments
 (0)