{"id":25021009,"url":"https://github.com/community-of-python/stompman","last_synced_at":"2026-03-15T17:23:41.959Z","repository":{"id":243178253,"uuid":"811558141","full_name":"community-of-python/stompman","owner":"community-of-python","description":"Good Python STOMP client \u0026 FastStream broker","archived":false,"fork":false,"pushed_at":"2025-03-24T18:30:52.000Z","size":254,"stargazers_count":12,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-31T21:31:35.772Z","etag":null,"topics":["activemq","artemis","artemis-mq","faststream","jms","messaging","stomp","stomp-client"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/community-of-python.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-06T20:41:52.000Z","updated_at":"2025-03-24T18:30:39.000Z","dependencies_parsed_at":"2025-02-04T13:04:15.831Z","dependency_job_id":"b51e6815-4f17-49bf-a1a3-5fd762a2dbf7","html_url":"https://github.com/community-of-python/stompman","commit_stats":null,"previous_names":["vrslev/stompman","community-of-python/stompman"],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/community-of-python%2Fstompman","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/community-of-python%2Fstompman/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/community-of-python%2Fstompman/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/community-of-python%2Fstompman/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/community-of-python","download_url":"https://codeload.github.com/community-of-python/stompman/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248665782,"owners_count":21142122,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activemq","artemis","artemis-mq","faststream","jms","messaging","stomp","stomp-client"],"created_at":"2025-02-05T12:18:38.451Z","updated_at":"2026-03-15T17:23:41.954Z","avatar_url":"https://github.com/community-of-python.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# stompman\n\nA Python client for STOMP asynchronous messaging protocol that is:\n\n- asynchronous,\n- not abandoned,\n- has typed, modern, comprehensible API.\n\n## How To Use\n\nBefore you start using stompman, make sure you have it installed. If you optionally want to use\nstompman over a websocket, you can install with `stompman[ws]` instead of `stompman`:\n\n```sh\nuv add stompman\npoetry add stompman\n```\n\nInitialize a client:\n\n```python\nasync with stompman.Client(\n    servers=[\n        stompman.ConnectionParameters(host=\"171.0.0.1\", port=61616, login=\"user1\", passcode=\"passcode1\"),\n        stompman.ConnectionParameters(host=\"172.0.0.1\", port=61616, login=\"user2\", passcode=\"passcode2\"),\n    ],\n\n\n    # SSL — can be either `None` (default), `True`, or `ssl.SSLContext'\n    ssl=None,\n\n    # Error frame handler:\n    on_error_frame=lambda error_frame: print(error_frame.body),\n\n    # Optional parameters with sensible defaults:\n    heartbeat=stompman.Heartbeat(will_send_interval_ms=1000, want_to_receive_interval_ms=1000),\n    connect_retry_attempts=3,\n    connect_retry_interval=1,\n    connect_timeout=2,\n    connection_confirmation_timeout=2,\n    disconnect_confirmation_timeout=2,\n    write_retry_attempts=3,\n    check_server_alive_interval_factor=3,\n) as client:\n    ...\n```\n\nInitialize a client with a custom connection class, for example, connecting to a stomp producer\nover websocket:\n\n```python\n# uv/poetry add stompman[ws] to get WebScoketConnection support\nfrom stompman.connection_ws import WebSocketConnection\n\nasync with stompman.Client(\n    servers=[\n        stompman.ConnectionParameters(host=\"171.0.0.1\", port=8080, login=\"\", passcode=\"\", ws_uri_path=\"/ws/path\"),\n    ],\n    connection_class=WebSocketConnection,\n    ...\n) as client:\n    ...\n```\n\n### Sending Messages\n\nTo send a message, use the following code:\n\n```python\nawait client.send(b\"hi there!\", destination=\"DLQ\", headers={\"persistent\": \"true\"})\n```\n\nOr, to send messages in a transaction:\n\n```python\nasync with client.begin() as transaction:\n    for _ in range(10):\n        await transaction.send(body=b\"hi there!\", destination=\"DLQ\", headers={\"persistent\": \"true\"})\n        await asyncio.sleep(0.1)\n```\n\n### Listening for Messages\n\nNow, let's subscribe to a destination and listen for messages:\n\n```python\nasync def handle_message_from_dlq(message_frame: stompman.MessageFrame) -\u003e None:\n    print(message_frame.body)\n\n\nawait client.subscribe(\"DLQ\", handle_message_from_dlq, on_suppressed_exception=print)\n```\n\nEntered `stompman.Client` will block forever waiting for messages if there are any active subscriptions.\n\nSometimes it's useful to avoid that:\n\n```python\ndlq_subscription = await client.subscribe(\"DLQ\", handle_message_from_dlq, on_suppressed_exception=print)\nawait dlq_subscription.unsubscribe()\n```\n\nBy default, subscription have ACK mode \"client-individual\". If handler successfully processes the message, an `ACK` frame will be sent. If handler raises an exception, a `NACK` frame will be sent. You can catch (and log) exceptions using `on_suppressed_exception` parameter:\n\n```python\nawait client.subscribe(\n    \"DLQ\",\n    handle_message_from_dlq,\n    on_suppressed_exception=lambda exception, message_frame: print(exception, message_frame),\n)\n```\n\nYou can change the ack mode used by specifying the `ack` parameter:\n\n```python\n# Server will assume that all messages sent to the subscription before the ACK'ed message are received and processed:\nawait client.subscribe(\"DLQ\", handle_message_from_dlq, ack=\"client\", on_suppressed_exception=print)\n\n# Server will assume that messages are received as soon as it send them to client:\nawait client.subscribe(\"DLQ\", handle_message_from_dlq, ack=\"auto\", on_suppressed_exception=print)\n```\n\nYou can pass custom headers to `client.subscribe()`:\n\n```python\nawait client.subscribe(\"DLQ\", handle_message_from_dlq, ack=\"client\", headers={\"selector\": \"location = 'Europe'\"}, on_suppressed_exception=print)\n```\n\n#### Handling ACK/NACKs yourself\n\nIf you want to send ACK and NACK frames yourself, you can use `client.subscribe_with_manual_ack()`:\n\n```python\nasync def handle_message_from_dlq(message_frame: stompman.AckableMessageFrame) -\u003e None:\n    print(message_frame.body)\n    await message_frame.ack()\n\nawait client.subscribe_with_manual_ack(\"DLQ\", handle_message_from_dlq, ack=\"client\")\n```\n\nNote that this way exceptions won't be suppressed automatically.\n\n### Cleaning Up\n\nstompman takes care of cleaning up resources automatically. When you leave the context of async context managers `stompman.Client()`, or `client.begin()`, the necessary frames will be sent to the server.\n\n### Handling Connectivity Issues\n\n- If multiple servers were provided, stompman will attempt to connect to each one simultaneously and will use the first that succeeds. If all servers fail to connect, an `stompman.FailedAllConnectAttemptsError` will be raised. In normal situation it doesn't need to be handled: tune retry and timeout parameters in `stompman.Client()` to your needs.\n\n- When connection is lost, stompman will attempt to handle it automatically. `stompman.FailedAllConnectAttemptsError` will be raised if all connection attempts fail. `stompman.FailedAllWriteAttemptsError` will be raised if connection succeeds but sending a frame or heartbeat lead to losing connection.\n- To implement health checks, use `stompman.Client.is_alive()` — it will return `True` if everything is OK and `False` if server is not responding.\n- `stompman` will write log warnings when connection is lost, after successful reconnection or invalid state during ack/nack.\n\n### ...and caveats\n\n- stompman supports Python 3.11 and newer.\n- It implements [STOMP 1.2](https://stomp.github.io/stomp-specification-1.2.html) — the latest version of the protocol.\n- Heartbeats are required, and sent automatically in background (defaults to 1 second).\n\nAlso, I want to pointed out that:\n\n- Protocol parsing is inspired by [aiostomp](https://github.com/pedrokiefer/aiostomp/blob/3449dcb53f43e5956ccc7662bb5b7d76bc6ef36b/aiostomp/protocol.py) (meaning: consumed by me and refactored from).\n- stompman is tested and used with [ActiveMQ Artemis](https://activemq.apache.org/components/artemis/) and [ActiveMQ Classic](https://activemq.apache.org/components/classic/).\n    - Caveat: a message sent by a Stomp client is converted into a JMS `TextMessage`/`BytesMessage` based on the `content-length` header (see the docs [here](https://activemq.apache.org/components/classic/documentation/stomp)). In order to send a `TextMessage`, `Client.send` needs to be invoked with `add_content_length` header set to `False`\n- 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).\n\n### FastStream STOMP broker\n\n[An implementation of STOMP broker for FastStream.](packages/faststream-stomp/README.md)\n\n### Examples\n\nSee examples in [examples/](examples).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcommunity-of-python%2Fstompman","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcommunity-of-python%2Fstompman","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcommunity-of-python%2Fstompman/lists"}