apm-component 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- apm_component/__init__.py +0 -0
- apm_component/broker_rabbitmq_aio_pika_async.py +697 -0
- apm_component/broker_rabbitmq_pika.py +625 -0
- apm_component/cache_memcache_pymemcache.py +433 -0
- apm_component/cache_memcache_python_memcached.py +391 -0
- apm_component/cache_redis_aioredis_async.py +577 -0
- apm_component/cache_redis_aredis_async.py +545 -0
- apm_component/cache_redis_redis.py +654 -0
- apm_component/config.py +137 -0
- apm_component/db_mssql_pymssql.py +523 -0
- apm_component/db_mssql_pyodbc.py +601 -0
- apm_component/db_mysql_aiomysql_async.py +635 -0
- apm_component/db_mysql_mysql_connector_python.py +520 -0
- apm_component/db_mysql_mysqlclient.py +542 -0
- apm_component/db_mysql_pymysql.py +535 -0
- apm_component/db_mysql_sqlalchemy.py +681 -0
- apm_component/db_sqlite_sqlite3.py +525 -0
- apm_component/ds_cassandra_cassandra_driver.py +634 -0
- apm_component/ds_elasticsearch_elasticsearch.py +571 -0
- apm_component/ds_mongodb_pymongo.py +713 -0
- apm_component/ds_oracle_oracledb.py +847 -0
- apm_component/ds_postgresql_asyncpg_async.py +647 -0
- apm_component/ds_postgresql_psycopg2.py +790 -0
- apm_component/http_aiohttp_async.py +442 -0
- apm_component/http_httpclient.py +516 -0
- apm_component/http_httplib2.py +303 -0
- apm_component/http_httpx.py +318 -0
- apm_component/http_requests.py +325 -0
- apm_component/http_urllib.py +334 -0
- apm_component/http_urllib3.py +292 -0
- apm_component/http_urls.py +83 -0
- apm_component/routes.py +47 -0
- apm_component-1.0.0.dist-info/METADATA +33 -0
- apm_component-1.0.0.dist-info/RECORD +36 -0
- apm_component-1.0.0.dist-info/WHEEL +5 -0
- apm_component-1.0.0.dist-info/top_level.txt +1 -0
|
File without changes
|
|
@@ -0,0 +1,697 @@
|
|
|
1
|
+
"""
|
|
2
|
+
RabbitMQ Broker Component - aio_pika module (async)
|
|
3
|
+
Covers: async connection, errors, queue/exchange management, publish, consume,
|
|
4
|
+
ack/nack, message properties, bulk publish, dead letter, serialization
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import asyncio
|
|
8
|
+
import json
|
|
9
|
+
import time
|
|
10
|
+
import aio_pika
|
|
11
|
+
from apm_component.config import get_rabbitmq_config
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
_PREFIX = "ct_aiopika_"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# ---------------------------------------------------------------------------
|
|
18
|
+
# Connection helpers
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
def _get_config():
|
|
21
|
+
return get_rabbitmq_config()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _get_url():
|
|
25
|
+
cfg = _get_config()
|
|
26
|
+
return f"amqp://{cfg['user']}:{cfg['password']}@{cfg['host']}:{cfg['port']}{cfg['vhost']}"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _queue_name(suffix):
|
|
30
|
+
return f"{_PREFIX}{suffix}"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _exchange_name(suffix):
|
|
34
|
+
return f"{_PREFIX}ex_{suffix}"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# ---------------------------------------------------------------------------
|
|
38
|
+
# Connection
|
|
39
|
+
# ---------------------------------------------------------------------------
|
|
40
|
+
async def _connect():
|
|
41
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
42
|
+
try:
|
|
43
|
+
channel = await conn.channel()
|
|
44
|
+
return {"status": "connected", "is_closed": conn.is_closed}
|
|
45
|
+
finally:
|
|
46
|
+
await conn.close()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def connect():
|
|
50
|
+
return asyncio.run(_connect())
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
async def _connect_basic():
|
|
54
|
+
conn = await aio_pika.connect(_get_url())
|
|
55
|
+
try:
|
|
56
|
+
return {"status": "connected_basic", "is_closed": conn.is_closed}
|
|
57
|
+
finally:
|
|
58
|
+
await conn.close()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def connect_basic():
|
|
62
|
+
return asyncio.run(_connect_basic())
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# ---------------------------------------------------------------------------
|
|
66
|
+
# Connection error scenarios
|
|
67
|
+
# ---------------------------------------------------------------------------
|
|
68
|
+
async def _connect_error_wrong_host():
|
|
69
|
+
cfg = _get_config()
|
|
70
|
+
url = f"amqp://{cfg['user']}:{cfg['password']}@192.0.2.1:5672/"
|
|
71
|
+
try:
|
|
72
|
+
conn = await asyncio.wait_for(aio_pika.connect(url), timeout=3)
|
|
73
|
+
await conn.close()
|
|
74
|
+
return {"status": "unexpected_success"}
|
|
75
|
+
except Exception as e:
|
|
76
|
+
return {"status": "error", "msg": str(e)}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def connect_error_wrong_host():
|
|
80
|
+
return asyncio.run(_connect_error_wrong_host())
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
async def _connect_error_wrong_port():
|
|
84
|
+
cfg = _get_config()
|
|
85
|
+
url = f"amqp://{cfg['user']}:{cfg['password']}@{cfg['host']}:55672/"
|
|
86
|
+
try:
|
|
87
|
+
conn = await asyncio.wait_for(aio_pika.connect(url), timeout=3)
|
|
88
|
+
await conn.close()
|
|
89
|
+
return {"status": "unexpected_success"}
|
|
90
|
+
except Exception as e:
|
|
91
|
+
return {"status": "error", "msg": str(e)}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def connect_error_wrong_port():
|
|
95
|
+
return asyncio.run(_connect_error_wrong_port())
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
async def _connect_error_wrong_credentials():
|
|
99
|
+
cfg = _get_config()
|
|
100
|
+
url = f"amqp://bad_user:bad_pass@{cfg['host']}:{cfg['port']}/"
|
|
101
|
+
try:
|
|
102
|
+
conn = await asyncio.wait_for(aio_pika.connect(url), timeout=5)
|
|
103
|
+
await conn.close()
|
|
104
|
+
return {"status": "unexpected_success"}
|
|
105
|
+
except Exception as e:
|
|
106
|
+
return {"status": "error", "msg": str(e)}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def connect_error_wrong_credentials():
|
|
110
|
+
return asyncio.run(_connect_error_wrong_credentials())
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# ---------------------------------------------------------------------------
|
|
114
|
+
# Queue management
|
|
115
|
+
# ---------------------------------------------------------------------------
|
|
116
|
+
async def _declare_queue():
|
|
117
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
118
|
+
try:
|
|
119
|
+
channel = await conn.channel()
|
|
120
|
+
q = await channel.declare_queue(_queue_name("basic"), durable=True)
|
|
121
|
+
return {
|
|
122
|
+
"status": "queue_declared",
|
|
123
|
+
"queue": q.name,
|
|
124
|
+
"message_count": q.declaration_result.message_count,
|
|
125
|
+
"consumer_count": q.declaration_result.consumer_count,
|
|
126
|
+
}
|
|
127
|
+
finally:
|
|
128
|
+
await conn.close()
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def declare_queue():
|
|
132
|
+
return asyncio.run(_declare_queue())
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
async def _purge_queue():
|
|
136
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
137
|
+
try:
|
|
138
|
+
channel = await conn.channel()
|
|
139
|
+
q = await channel.declare_queue(_queue_name("basic"), durable=True)
|
|
140
|
+
purged = await q.purge()
|
|
141
|
+
return {"status": "queue_purged", "messages_purged": purged}
|
|
142
|
+
finally:
|
|
143
|
+
await conn.close()
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def purge_queue():
|
|
147
|
+
return asyncio.run(_purge_queue())
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
async def _delete_queue():
|
|
151
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
152
|
+
try:
|
|
153
|
+
channel = await conn.channel()
|
|
154
|
+
q = await channel.declare_queue(_queue_name("delete_test"))
|
|
155
|
+
await q.delete()
|
|
156
|
+
return {"status": "queue_deleted"}
|
|
157
|
+
finally:
|
|
158
|
+
await conn.close()
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def delete_queue():
|
|
162
|
+
return asyncio.run(_delete_queue())
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
# ---------------------------------------------------------------------------
|
|
166
|
+
# Exchange management
|
|
167
|
+
# ---------------------------------------------------------------------------
|
|
168
|
+
async def _declare_exchange():
|
|
169
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
170
|
+
try:
|
|
171
|
+
channel = await conn.channel()
|
|
172
|
+
ex = await channel.declare_exchange(
|
|
173
|
+
_exchange_name("direct"), aio_pika.ExchangeType.DIRECT, durable=True
|
|
174
|
+
)
|
|
175
|
+
return {"status": "exchange_declared", "exchange": ex.name}
|
|
176
|
+
finally:
|
|
177
|
+
await conn.close()
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def declare_exchange():
|
|
181
|
+
return asyncio.run(_declare_exchange())
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
async def _bind_queue_to_exchange():
|
|
185
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
186
|
+
try:
|
|
187
|
+
channel = await conn.channel()
|
|
188
|
+
ex = await channel.declare_exchange(
|
|
189
|
+
_exchange_name("direct"), aio_pika.ExchangeType.DIRECT, durable=True
|
|
190
|
+
)
|
|
191
|
+
q = await channel.declare_queue(_queue_name("bound"), durable=True)
|
|
192
|
+
await q.bind(ex, routing_key="test_key")
|
|
193
|
+
return {"status": "queue_bound", "queue": q.name, "exchange": ex.name, "routing_key": "test_key"}
|
|
194
|
+
finally:
|
|
195
|
+
await conn.close()
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def bind_queue_to_exchange():
|
|
199
|
+
return asyncio.run(_bind_queue_to_exchange())
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
async def _delete_exchange():
|
|
203
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
204
|
+
try:
|
|
205
|
+
channel = await conn.channel()
|
|
206
|
+
ex = await channel.declare_exchange(
|
|
207
|
+
_exchange_name("del_test"), aio_pika.ExchangeType.FANOUT
|
|
208
|
+
)
|
|
209
|
+
await ex.delete()
|
|
210
|
+
return {"status": "exchange_deleted"}
|
|
211
|
+
finally:
|
|
212
|
+
await conn.close()
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def delete_exchange():
|
|
216
|
+
return asyncio.run(_delete_exchange())
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
# ---------------------------------------------------------------------------
|
|
220
|
+
# Publishing
|
|
221
|
+
# ---------------------------------------------------------------------------
|
|
222
|
+
async def _publish_basic():
|
|
223
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
224
|
+
try:
|
|
225
|
+
channel = await conn.channel()
|
|
226
|
+
q = await channel.declare_queue(_queue_name("pub_basic"), durable=True)
|
|
227
|
+
await q.purge()
|
|
228
|
+
await channel.default_exchange.publish(
|
|
229
|
+
aio_pika.Message(body=b"hello aio_pika", delivery_mode=aio_pika.DeliveryMode.PERSISTENT),
|
|
230
|
+
routing_key=q.name,
|
|
231
|
+
)
|
|
232
|
+
return {"status": "published"}
|
|
233
|
+
finally:
|
|
234
|
+
await conn.close()
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def publish_basic():
|
|
238
|
+
return asyncio.run(_publish_basic())
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
async def _publish_to_exchange():
|
|
242
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
243
|
+
try:
|
|
244
|
+
channel = await conn.channel()
|
|
245
|
+
ex = await channel.declare_exchange(
|
|
246
|
+
_exchange_name("pub"), aio_pika.ExchangeType.DIRECT, durable=True
|
|
247
|
+
)
|
|
248
|
+
q = await channel.declare_queue(_queue_name("pub_ex"), durable=True)
|
|
249
|
+
await q.bind(ex, routing_key="pub_key")
|
|
250
|
+
await q.purge()
|
|
251
|
+
await ex.publish(
|
|
252
|
+
aio_pika.Message(body=b"exchange message", delivery_mode=aio_pika.DeliveryMode.PERSISTENT),
|
|
253
|
+
routing_key="pub_key",
|
|
254
|
+
)
|
|
255
|
+
return {"status": "published_to_exchange"}
|
|
256
|
+
finally:
|
|
257
|
+
await conn.close()
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def publish_to_exchange():
|
|
261
|
+
return asyncio.run(_publish_to_exchange())
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
async def _publish_with_properties():
|
|
265
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
266
|
+
try:
|
|
267
|
+
channel = await conn.channel()
|
|
268
|
+
q = await channel.declare_queue(_queue_name("pub_props"), durable=True)
|
|
269
|
+
await q.purge()
|
|
270
|
+
msg = aio_pika.Message(
|
|
271
|
+
body=json.dumps({"key": "value"}).encode(),
|
|
272
|
+
delivery_mode=aio_pika.DeliveryMode.PERSISTENT,
|
|
273
|
+
content_type="application/json",
|
|
274
|
+
headers={"x-custom": "test_header"},
|
|
275
|
+
priority=5,
|
|
276
|
+
expiration=60,
|
|
277
|
+
)
|
|
278
|
+
await channel.default_exchange.publish(msg, routing_key=q.name)
|
|
279
|
+
return {"status": "published_with_properties"}
|
|
280
|
+
finally:
|
|
281
|
+
await conn.close()
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def publish_with_properties():
|
|
285
|
+
return asyncio.run(_publish_with_properties())
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
async def _publish_bulk():
|
|
289
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
290
|
+
try:
|
|
291
|
+
channel = await conn.channel()
|
|
292
|
+
q = await channel.declare_queue(_queue_name("pub_bulk"), durable=True)
|
|
293
|
+
await q.purge()
|
|
294
|
+
count = 10
|
|
295
|
+
for i in range(count):
|
|
296
|
+
await channel.default_exchange.publish(
|
|
297
|
+
aio_pika.Message(body=f"bulk_msg_{i}".encode(), delivery_mode=aio_pika.DeliveryMode.PERSISTENT),
|
|
298
|
+
routing_key=q.name,
|
|
299
|
+
)
|
|
300
|
+
return {"status": "bulk_published", "count": count}
|
|
301
|
+
finally:
|
|
302
|
+
await conn.close()
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def publish_bulk():
|
|
306
|
+
return asyncio.run(_publish_bulk())
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
async def _publish_json():
|
|
310
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
311
|
+
try:
|
|
312
|
+
channel = await conn.channel()
|
|
313
|
+
q = await channel.declare_queue(_queue_name("pub_json"), durable=True)
|
|
314
|
+
await q.purge()
|
|
315
|
+
payload = {"name": "test", "values": [1, 2, 3], "nested": {"a": True}}
|
|
316
|
+
msg = aio_pika.Message(
|
|
317
|
+
body=json.dumps(payload).encode(),
|
|
318
|
+
content_type="application/json",
|
|
319
|
+
delivery_mode=aio_pika.DeliveryMode.PERSISTENT,
|
|
320
|
+
)
|
|
321
|
+
await channel.default_exchange.publish(msg, routing_key=q.name)
|
|
322
|
+
return {"status": "json_published"}
|
|
323
|
+
finally:
|
|
324
|
+
await conn.close()
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
def publish_json():
|
|
328
|
+
return asyncio.run(_publish_json())
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
# ---------------------------------------------------------------------------
|
|
332
|
+
# Consuming
|
|
333
|
+
# ---------------------------------------------------------------------------
|
|
334
|
+
async def _consume_basic_get():
|
|
335
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
336
|
+
try:
|
|
337
|
+
channel = await conn.channel()
|
|
338
|
+
q = await channel.declare_queue(_queue_name("pub_basic"), durable=True)
|
|
339
|
+
await q.purge()
|
|
340
|
+
await channel.default_exchange.publish(
|
|
341
|
+
aio_pika.Message(body=b"consume_me"),
|
|
342
|
+
routing_key=q.name,
|
|
343
|
+
)
|
|
344
|
+
msg = await q.get(timeout=5)
|
|
345
|
+
if msg:
|
|
346
|
+
await msg.ack()
|
|
347
|
+
return {"status": "consumed", "body": msg.body.decode()}
|
|
348
|
+
return {"status": "no_message"}
|
|
349
|
+
finally:
|
|
350
|
+
await conn.close()
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def consume_basic_get():
|
|
354
|
+
return asyncio.run(_consume_basic_get())
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
async def _consume_with_ack():
|
|
358
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
359
|
+
try:
|
|
360
|
+
channel = await conn.channel()
|
|
361
|
+
q = await channel.declare_queue(_queue_name("ack_test"), durable=True)
|
|
362
|
+
await q.purge()
|
|
363
|
+
await channel.default_exchange.publish(
|
|
364
|
+
aio_pika.Message(body=b"ack_me"),
|
|
365
|
+
routing_key=q.name,
|
|
366
|
+
)
|
|
367
|
+
msg = await q.get(timeout=5)
|
|
368
|
+
if msg:
|
|
369
|
+
await msg.ack()
|
|
370
|
+
return {"status": "consumed_acked", "body": msg.body.decode()}
|
|
371
|
+
return {"status": "no_message"}
|
|
372
|
+
finally:
|
|
373
|
+
await conn.close()
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def consume_with_ack():
|
|
377
|
+
return asyncio.run(_consume_with_ack())
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
async def _consume_with_nack():
|
|
381
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
382
|
+
try:
|
|
383
|
+
channel = await conn.channel()
|
|
384
|
+
q = await channel.declare_queue(_queue_name("nack_test"), durable=True)
|
|
385
|
+
await q.purge()
|
|
386
|
+
await channel.default_exchange.publish(
|
|
387
|
+
aio_pika.Message(body=b"nack_me"),
|
|
388
|
+
routing_key=q.name,
|
|
389
|
+
)
|
|
390
|
+
msg = await q.get(timeout=5)
|
|
391
|
+
if msg:
|
|
392
|
+
await msg.nack(requeue=False)
|
|
393
|
+
return {"status": "consumed_nacked", "body": msg.body.decode()}
|
|
394
|
+
return {"status": "no_message"}
|
|
395
|
+
finally:
|
|
396
|
+
await conn.close()
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def consume_with_nack():
|
|
400
|
+
return asyncio.run(_consume_with_nack())
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
async def _consume_with_reject():
|
|
404
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
405
|
+
try:
|
|
406
|
+
channel = await conn.channel()
|
|
407
|
+
q = await channel.declare_queue(_queue_name("reject_test"), durable=True)
|
|
408
|
+
await q.purge()
|
|
409
|
+
await channel.default_exchange.publish(
|
|
410
|
+
aio_pika.Message(body=b"reject_me"),
|
|
411
|
+
routing_key=q.name,
|
|
412
|
+
)
|
|
413
|
+
msg = await q.get(timeout=5)
|
|
414
|
+
if msg:
|
|
415
|
+
await msg.reject(requeue=False)
|
|
416
|
+
return {"status": "consumed_rejected", "body": msg.body.decode()}
|
|
417
|
+
return {"status": "no_message"}
|
|
418
|
+
finally:
|
|
419
|
+
await conn.close()
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
def consume_with_reject():
|
|
423
|
+
return asyncio.run(_consume_with_reject())
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
async def _consume_with_qos():
|
|
427
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
428
|
+
try:
|
|
429
|
+
channel = await conn.channel()
|
|
430
|
+
await channel.set_qos(prefetch_count=2)
|
|
431
|
+
q = await channel.declare_queue(_queue_name("qos_test"), durable=True)
|
|
432
|
+
await q.purge()
|
|
433
|
+
for i in range(5):
|
|
434
|
+
await channel.default_exchange.publish(
|
|
435
|
+
aio_pika.Message(body=f"qos_{i}".encode()),
|
|
436
|
+
routing_key=q.name,
|
|
437
|
+
)
|
|
438
|
+
messages = []
|
|
439
|
+
for _ in range(2):
|
|
440
|
+
msg = await q.get(timeout=5)
|
|
441
|
+
if msg:
|
|
442
|
+
messages.append(msg.body.decode())
|
|
443
|
+
await msg.ack()
|
|
444
|
+
return {"status": "qos_consumed", "messages": messages, "count": len(messages)}
|
|
445
|
+
finally:
|
|
446
|
+
await conn.close()
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
def consume_with_qos():
|
|
450
|
+
return asyncio.run(_consume_with_qos())
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
async def _consume_json():
|
|
454
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
455
|
+
try:
|
|
456
|
+
channel = await conn.channel()
|
|
457
|
+
q = await channel.declare_queue(_queue_name("pub_json"), durable=True)
|
|
458
|
+
await q.purge()
|
|
459
|
+
payload = {"type": "json_test", "data": [1, 2, 3]}
|
|
460
|
+
await channel.default_exchange.publish(
|
|
461
|
+
aio_pika.Message(
|
|
462
|
+
body=json.dumps(payload).encode(),
|
|
463
|
+
content_type="application/json",
|
|
464
|
+
),
|
|
465
|
+
routing_key=q.name,
|
|
466
|
+
)
|
|
467
|
+
msg = await q.get(timeout=5)
|
|
468
|
+
if msg:
|
|
469
|
+
await msg.ack()
|
|
470
|
+
parsed = json.loads(msg.body.decode())
|
|
471
|
+
return {"status": "json_consumed", "payload": parsed}
|
|
472
|
+
return {"status": "no_message"}
|
|
473
|
+
finally:
|
|
474
|
+
await conn.close()
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
def consume_json():
|
|
478
|
+
return asyncio.run(_consume_json())
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
# ---------------------------------------------------------------------------
|
|
482
|
+
# Publisher confirms (enabled by default in aio_pika)
|
|
483
|
+
# ---------------------------------------------------------------------------
|
|
484
|
+
async def _publish_with_confirm():
|
|
485
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
486
|
+
try:
|
|
487
|
+
channel = await conn.channel()
|
|
488
|
+
q = await channel.declare_queue(_queue_name("confirm_test"), durable=True)
|
|
489
|
+
await q.purge()
|
|
490
|
+
await channel.default_exchange.publish(
|
|
491
|
+
aio_pika.Message(body=b"confirmed_msg", delivery_mode=aio_pika.DeliveryMode.PERSISTENT),
|
|
492
|
+
routing_key=q.name,
|
|
493
|
+
)
|
|
494
|
+
return {"status": "publish_confirmed"}
|
|
495
|
+
finally:
|
|
496
|
+
await conn.close()
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
def publish_with_confirm():
|
|
500
|
+
return asyncio.run(_publish_with_confirm())
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
# ---------------------------------------------------------------------------
|
|
504
|
+
# Dead letter queue
|
|
505
|
+
# ---------------------------------------------------------------------------
|
|
506
|
+
async def _dead_letter_queue():
|
|
507
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
508
|
+
try:
|
|
509
|
+
channel = await conn.channel()
|
|
510
|
+
dlx = await channel.declare_exchange(
|
|
511
|
+
_exchange_name("dlx"), aio_pika.ExchangeType.DIRECT, durable=True
|
|
512
|
+
)
|
|
513
|
+
dlq = await channel.declare_queue(_queue_name("dlq"), durable=True)
|
|
514
|
+
await dlq.bind(dlx, routing_key="dead")
|
|
515
|
+
|
|
516
|
+
main_q_name = _queue_name("dl_main")
|
|
517
|
+
try:
|
|
518
|
+
temp_q = await channel.declare_queue(main_q_name, passive=True)
|
|
519
|
+
await temp_q.delete()
|
|
520
|
+
except Exception:
|
|
521
|
+
pass
|
|
522
|
+
|
|
523
|
+
channel = await conn.channel()
|
|
524
|
+
main_q = await channel.declare_queue(
|
|
525
|
+
main_q_name,
|
|
526
|
+
durable=True,
|
|
527
|
+
arguments={
|
|
528
|
+
"x-dead-letter-exchange": _exchange_name("dlx"),
|
|
529
|
+
"x-dead-letter-routing-key": "dead",
|
|
530
|
+
},
|
|
531
|
+
)
|
|
532
|
+
await dlq.purge()
|
|
533
|
+
|
|
534
|
+
await channel.default_exchange.publish(
|
|
535
|
+
aio_pika.Message(body=b"will_be_dead_lettered"),
|
|
536
|
+
routing_key=main_q.name,
|
|
537
|
+
)
|
|
538
|
+
msg = await main_q.get(timeout=5)
|
|
539
|
+
if msg:
|
|
540
|
+
await msg.nack(requeue=False)
|
|
541
|
+
|
|
542
|
+
await asyncio.sleep(0.5)
|
|
543
|
+
|
|
544
|
+
dl_msg = await dlq.get(timeout=5)
|
|
545
|
+
if dl_msg:
|
|
546
|
+
await dl_msg.ack()
|
|
547
|
+
return {"status": "dead_letter_ok", "body": dl_msg.body.decode()}
|
|
548
|
+
return {"status": "dead_letter_no_message"}
|
|
549
|
+
finally:
|
|
550
|
+
await conn.close()
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
def dead_letter_queue():
|
|
554
|
+
return asyncio.run(_dead_letter_queue())
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
# ---------------------------------------------------------------------------
|
|
558
|
+
# Error scenarios
|
|
559
|
+
# ---------------------------------------------------------------------------
|
|
560
|
+
async def _error_consume_nonexistent_queue():
|
|
561
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
562
|
+
try:
|
|
563
|
+
channel = await conn.channel()
|
|
564
|
+
try:
|
|
565
|
+
await channel.declare_queue("nonexistent_q_xyz_12345", passive=True)
|
|
566
|
+
return {"status": "unexpected_success"}
|
|
567
|
+
except Exception as e:
|
|
568
|
+
return {"status": "error", "msg": str(e)}
|
|
569
|
+
finally:
|
|
570
|
+
await conn.close()
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
def error_consume_nonexistent_queue():
|
|
574
|
+
return asyncio.run(_error_consume_nonexistent_queue())
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
# ---------------------------------------------------------------------------
|
|
578
|
+
# Unique / advanced
|
|
579
|
+
# ---------------------------------------------------------------------------
|
|
580
|
+
async def _delayed_publish():
|
|
581
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
582
|
+
try:
|
|
583
|
+
channel = await conn.channel()
|
|
584
|
+
q = await channel.declare_queue(_queue_name("delayed"), durable=True)
|
|
585
|
+
await q.purge()
|
|
586
|
+
await asyncio.sleep(1)
|
|
587
|
+
await channel.default_exchange.publish(
|
|
588
|
+
aio_pika.Message(body=b"delayed_msg"),
|
|
589
|
+
routing_key=q.name,
|
|
590
|
+
)
|
|
591
|
+
msg = await q.get(timeout=5)
|
|
592
|
+
if msg:
|
|
593
|
+
await msg.ack()
|
|
594
|
+
return {"status": "delayed_publish_ok", "body": msg.body.decode()}
|
|
595
|
+
return {"status": "no_message"}
|
|
596
|
+
finally:
|
|
597
|
+
await conn.close()
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
def delayed_publish():
|
|
601
|
+
return asyncio.run(_delayed_publish())
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
async def _publish_binary():
|
|
605
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
606
|
+
try:
|
|
607
|
+
channel = await conn.channel()
|
|
608
|
+
q = await channel.declare_queue(_queue_name("binary"), durable=True)
|
|
609
|
+
await q.purge()
|
|
610
|
+
binary_data = bytes(range(256))
|
|
611
|
+
await channel.default_exchange.publish(
|
|
612
|
+
aio_pika.Message(body=binary_data, content_type="application/octet-stream"),
|
|
613
|
+
routing_key=q.name,
|
|
614
|
+
)
|
|
615
|
+
msg = await q.get(timeout=5)
|
|
616
|
+
if msg:
|
|
617
|
+
await msg.ack()
|
|
618
|
+
return {"status": "binary_ok", "length": len(msg.body)}
|
|
619
|
+
return {"status": "no_message"}
|
|
620
|
+
finally:
|
|
621
|
+
await conn.close()
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
def publish_binary():
|
|
625
|
+
return asyncio.run(_publish_binary())
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
# ---------------------------------------------------------------------------
|
|
629
|
+
# Cleanup helper
|
|
630
|
+
# ---------------------------------------------------------------------------
|
|
631
|
+
async def _cleanup():
|
|
632
|
+
conn = await aio_pika.connect_robust(_get_url())
|
|
633
|
+
try:
|
|
634
|
+
channel = await conn.channel()
|
|
635
|
+
queues = [
|
|
636
|
+
"basic", "pub_basic", "pub_ex", "pub_props", "pub_bulk", "pub_json",
|
|
637
|
+
"ack_test", "nack_test", "reject_test", "qos_test", "confirm_test",
|
|
638
|
+
"dl_main", "dlq", "delete_test", "bound", "delayed", "binary",
|
|
639
|
+
]
|
|
640
|
+
for q_suffix in queues:
|
|
641
|
+
try:
|
|
642
|
+
q = await channel.declare_queue(_queue_name(q_suffix), passive=True)
|
|
643
|
+
await q.delete()
|
|
644
|
+
except Exception:
|
|
645
|
+
channel = await conn.channel()
|
|
646
|
+
|
|
647
|
+
exchanges = ["direct", "pub", "dlx", "del_test"]
|
|
648
|
+
for ex_suffix in exchanges:
|
|
649
|
+
try:
|
|
650
|
+
ex = await channel.declare_exchange(
|
|
651
|
+
_exchange_name(ex_suffix), aio_pika.ExchangeType.DIRECT, passive=True
|
|
652
|
+
)
|
|
653
|
+
await ex.delete()
|
|
654
|
+
except Exception:
|
|
655
|
+
channel = await conn.channel()
|
|
656
|
+
return {"status": "cleanup_done"}
|
|
657
|
+
finally:
|
|
658
|
+
await conn.close()
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
def cleanup():
|
|
662
|
+
return asyncio.run(_cleanup())
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
# ---------------------------------------------------------------------------
|
|
666
|
+
# Global route-to-function mapping
|
|
667
|
+
# ---------------------------------------------------------------------------
|
|
668
|
+
ROUTE_MAP = {
|
|
669
|
+
"/broker/rabbitmq/aio_pika/connect": connect,
|
|
670
|
+
"/broker/rabbitmq/aio_pika/connect_basic": connect_basic,
|
|
671
|
+
"/broker/rabbitmq/aio_pika/connect_error_wrong_host": connect_error_wrong_host,
|
|
672
|
+
"/broker/rabbitmq/aio_pika/connect_error_wrong_port": connect_error_wrong_port,
|
|
673
|
+
"/broker/rabbitmq/aio_pika/connect_error_wrong_credentials": connect_error_wrong_credentials,
|
|
674
|
+
"/broker/rabbitmq/aio_pika/declare_queue": declare_queue,
|
|
675
|
+
"/broker/rabbitmq/aio_pika/purge_queue": purge_queue,
|
|
676
|
+
"/broker/rabbitmq/aio_pika/delete_queue": delete_queue,
|
|
677
|
+
"/broker/rabbitmq/aio_pika/declare_exchange": declare_exchange,
|
|
678
|
+
"/broker/rabbitmq/aio_pika/bind_queue_to_exchange": bind_queue_to_exchange,
|
|
679
|
+
"/broker/rabbitmq/aio_pika/delete_exchange": delete_exchange,
|
|
680
|
+
"/broker/rabbitmq/aio_pika/publish_basic": publish_basic,
|
|
681
|
+
"/broker/rabbitmq/aio_pika/publish_to_exchange": publish_to_exchange,
|
|
682
|
+
"/broker/rabbitmq/aio_pika/publish_with_properties": publish_with_properties,
|
|
683
|
+
"/broker/rabbitmq/aio_pika/publish_bulk": publish_bulk,
|
|
684
|
+
"/broker/rabbitmq/aio_pika/publish_json": publish_json,
|
|
685
|
+
"/broker/rabbitmq/aio_pika/consume_basic_get": consume_basic_get,
|
|
686
|
+
"/broker/rabbitmq/aio_pika/consume_with_ack": consume_with_ack,
|
|
687
|
+
"/broker/rabbitmq/aio_pika/consume_with_nack": consume_with_nack,
|
|
688
|
+
"/broker/rabbitmq/aio_pika/consume_with_reject": consume_with_reject,
|
|
689
|
+
"/broker/rabbitmq/aio_pika/consume_with_qos": consume_with_qos,
|
|
690
|
+
"/broker/rabbitmq/aio_pika/consume_json": consume_json,
|
|
691
|
+
"/broker/rabbitmq/aio_pika/publish_with_confirm": publish_with_confirm,
|
|
692
|
+
"/broker/rabbitmq/aio_pika/dead_letter_queue": dead_letter_queue,
|
|
693
|
+
"/broker/rabbitmq/aio_pika/error_consume_nonexistent_queue": error_consume_nonexistent_queue,
|
|
694
|
+
"/broker/rabbitmq/aio_pika/delayed_publish": delayed_publish,
|
|
695
|
+
"/broker/rabbitmq/aio_pika/publish_binary": publish_binary,
|
|
696
|
+
"/broker/rabbitmq/aio_pika/cleanup": cleanup,
|
|
697
|
+
}
|