Name | stompman JSON |
Version |
1.6.0
JSON |
| download |
home_page | None |
Summary | Python STOMP client with pleasant API |
upload_time | 2024-11-05 07:24:50 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.11 |
license | MIT |
keywords |
activemq
artemis
jms
messaging
stomp
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# stompman
A Python client for STOMP asynchronous messaging protocol that is:
- asynchronous,
- not abandoned,
- has typed, modern, comprehensible API.
## How To Use
Before you start using stompman, make sure you have it installed:
```sh
uv add stompman
poetry add stompman
```
Initialize a client:
```python
async with stompman.Client(
servers=[
stompman.ConnectionParameters(host="171.0.0.1", port=61616, login="user1", passcode="passcode1"),
stompman.ConnectionParameters(host="172.0.0.1", port=61616, login="user2", passcode="passcode2"),
],
# Handlers:
on_error_frame=lambda error_frame: print(error_frame.body),
on_heartbeat=lambda: print("Server sent a heartbeat"), # also can be async
# SSL — can be either `None` (default), `True`, or `ssl.SSLContext'
ssl=None,
# Optional parameters with sensible defaults:
heartbeat=stompman.Heartbeat(will_send_interval_ms=1000, want_to_receive_interval_ms=1000),
connect_retry_attempts=3,
connect_retry_interval=1,
connect_timeout=2,
connection_confirmation_timeout=2,
disconnect_confirmation_timeout=2,
read_timeout=2,
write_retry_attempts=3,
) as client:
...
```
### Sending Messages
To send a message, use the following code:
```python
await client.send(b"hi there!", destination="DLQ", headers={"persistent": "true"})
```
Or, to send messages in a transaction:
```python
async with client.begin() as transaction:
for _ in range(10):
await transaction.send(body=b"hi there!", destination="DLQ", headers={"persistent": "true"})
await asyncio.sleep(0.1)
```
### Listening for Messages
Now, let's subscribe to a destination and listen for messages:
```python
async def handle_message_from_dlq(message_frame: stompman.MessageFrame) -> None:
print(message_frame.body)
await client.subscribe("DLQ", handle_message_from_dlq, on_suppressed_exception=print)
```
Entered `stompman.Client` will block forever waiting for messages if there are any active subscriptions.
Sometimes it's useful to avoid that:
```python
dlq_subscription = await client.subscribe("DLQ", handle_message_from_dlq, on_suppressed_exception=print)
await dlq_subscription.unsubscribe()
```
By 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:
```python
await client.subscribe(
"DLQ",
handle_message_from_dlq,
on_suppressed_exception=lambda exception, message_frame: print(exception, message_frame),
)
```
You can change the ack mode used by specifying the `ack` parameter:
```python
# Server will assume that all messages sent to the subscription before the ACK'ed message are received and processed:
await client.subscribe("DLQ", handle_message_from_dlq, ack="client", on_suppressed_exception=print)
# Server will assume that messages are received as soon as it send them to client:
await client.subscribe("DLQ", handle_message_from_dlq, ack="auto", on_suppressed_exception=print)
```
You can pass custom headers to `client.subscribe()`:
```python
await client.subscribe("DLQ", handle_message_from_dlq, ack="client", headers={"selector": "location = 'Europe'"}, on_suppressed_exception=print)
```
### Cleaning Up
stompman 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.
### Handling Connectivity Issues
- 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.
- 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.
### ...and caveats
- stompman supports Python 3.11 and newer.
- It implements [STOMP 1.2](https://stomp.github.io/stomp-specification-1.2.html) — the latest version of the protocol.
- Heartbeats are required, and sent automatically in background (defaults to 1 second).
Also, I want to pointed out that:
- Protocol parsing is inspired by [aiostomp](https://github.com/pedrokiefer/aiostomp/blob/3449dcb53f43e5956ccc7662bb5b7d76bc6ef36b/aiostomp/protocol.py) (meaning: consumed by me and refactored from).
- stompman is tested and used with [ActiveMQ Artemis](https://activemq.apache.org/components/artemis/) and [ActiveMQ Classic](https://activemq.apache.org/components/classic/).
- 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).
### Examples
See producer and consumer examples in [examples/](examples).
Raw data
{
"_id": null,
"home_page": null,
"name": "stompman",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": "activemq, artemis, jms, messaging, stomp",
"author": null,
"author_email": "Lev Vereshchagin <mail@vrslev.com>",
"download_url": "https://files.pythonhosted.org/packages/a8/3d/49f5d2e11b024feb1bbe4b741168c7f945b591b8aefafa6b15eaedcf34ef/stompman-1.6.0.tar.gz",
"platform": null,
"description": "# 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:\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 # Handlers:\n on_error_frame=lambda error_frame: print(error_frame.body),\n on_heartbeat=lambda: print(\"Server sent a heartbeat\"), # also can be async\n\n # SSL \u2014 can be either `None` (default), `True`, or `ssl.SSLContext'\n ssl=None,\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 read_timeout=2,\n write_retry_attempts=3,\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) -> 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### 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\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) \u2014 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- 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### Examples\n\nSee producer and consumer examples in [examples/](examples).\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Python STOMP client with pleasant API",
"version": "1.6.0",
"project_urls": {
"repository": "https://github.com/vrslev/stompman"
},
"split_keywords": [
"activemq",
" artemis",
" jms",
" messaging",
" stomp"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "8fce3769c995ad3e2850b810393309f0ae73c5240d52504cb7f6d0aa3e999bcd",
"md5": "be22bf268b28c8d046eb66274c5f589c",
"sha256": "2d1a440b18e370559baae3ad02314a793674abdfeab5367ed6de0eb81a3fa526"
},
"downloads": -1,
"filename": "stompman-1.6.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "be22bf268b28c8d046eb66274c5f589c",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11",
"size": 17962,
"upload_time": "2024-11-05T07:24:49",
"upload_time_iso_8601": "2024-11-05T07:24:49.556728Z",
"url": "https://files.pythonhosted.org/packages/8f/ce/3769c995ad3e2850b810393309f0ae73c5240d52504cb7f6d0aa3e999bcd/stompman-1.6.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "a83d49f5d2e11b024feb1bbe4b741168c7f945b591b8aefafa6b15eaedcf34ef",
"md5": "f33810c846d2823388de4491d6d35026",
"sha256": "16e536d674b8c315e51ddbb877266fdd1b31ea6b00c4d13396f3d76051b85dfb"
},
"downloads": -1,
"filename": "stompman-1.6.0.tar.gz",
"has_sig": false,
"md5_digest": "f33810c846d2823388de4491d6d35026",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11",
"size": 25209,
"upload_time": "2024-11-05T07:24:50",
"upload_time_iso_8601": "2024-11-05T07:24:50.709160Z",
"url": "https://files.pythonhosted.org/packages/a8/3d/49f5d2e11b024feb1bbe4b741168c7f945b591b8aefafa6b15eaedcf34ef/stompman-1.6.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-11-05 07:24:50",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "vrslev",
"github_project": "stompman",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "stompman"
}