mq-bridge-py-basic 0.2.18__tar.gz → 0.2.20__tar.gz
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.
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/.github/workflows/release.yml +15 -4
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/Cargo.lock +31 -32
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/Cargo.toml +15 -5
- mq_bridge_py_basic-0.2.20/PKG-INFO +191 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/README.md +6 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/benches/performance_bench.rs +1 -1
- mq_bridge_py_basic-0.2.20/benches/router_bench.rs +275 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/mq-bridge.schema.json +102 -7
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/mq_bridge/__init__.py +4 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/mq_bridge/__init__.pyi +40 -2
- mq_bridge_py_basic-0.2.20/mq_bridge/config.py +98 -0
- mq_bridge_py_basic-0.2.20/mq_bridge/config.pyi +394 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/pyproject.toml +5 -3
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/python/mq-bridge-py/Cargo.toml +2 -1
- mq_bridge_py_basic-0.2.20/python/mq-bridge-py/README.md +167 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/python/mq-bridge-py/example.py +14 -13
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/python/mq-bridge-py/examples/raw_route.py +0 -1
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/python/mq-bridge-py/pyproject-basic.toml +5 -3
- mq_bridge_py_basic-0.2.20/python/mq-bridge-py/scripts/gen_config_types.py +248 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/python/mq-bridge-py/src/lib.rs +216 -41
- mq_bridge_py_basic-0.2.20/python/mq-bridge-py/tests/test_config_types.py +45 -0
- mq_bridge_py_basic-0.2.20/python/mq-bridge-py/tests/test_packaging.py +49 -0
- mq_bridge_py_basic-0.2.20/python/mq-bridge-py/tests/test_routes.py +143 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/python/mq-bridge-py/uv.lock +100 -1369
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/analysis/http/mq_bridge_http_profile.rs +24 -4
- mq_bridge_py_basic-0.2.20/scripts/analysis/http/run_http_ladder.sh +87 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/httparena/frameworks/mq-bridge-py/Dockerfile +1 -1
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/httparena/frameworks/mq-bridge-py/meta.json +7 -2
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/httparena/frameworks/mq-bridge-py/server.py +191 -32
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/grpc.rs +103 -32
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/http.rs +329 -53
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/mod.rs +113 -0
- mq_bridge_py_basic-0.2.20/src/endpoints/websocket.rs +783 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/middleware/buffer.rs +296 -2
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/middleware/mod.rs +2 -5
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/models.rs +77 -3
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/test_utils.rs +45 -11
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/websocket.rs +1 -1
- mq_bridge_py_basic-0.2.20/tests/websocket_test.rs +356 -0
- mq_bridge_py_basic-0.2.18/PKG-INFO +0 -110
- mq_bridge_py_basic-0.2.18/python/mq-bridge-py/README.md +0 -86
- mq_bridge_py_basic-0.2.18/src/endpoints/websocket.rs +0 -459
- mq_bridge_py_basic-0.2.18/tests/websocket_test.rs +0 -118
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/.github/workflows/benchmark.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/.github/workflows/ci.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/.github/workflows/ibm-mq.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/.github/workflows/publish-python.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/.github/workflows/python.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/.github/workflows/test-matrix.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/.gitignore +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/ARCHITECTURE.md +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/CONFIGURATION.md +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/CONTRIBUTING.md +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/LICENSE +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/LICENSE.python +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/build.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/claude.md +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/examples/ipc_worker_queue.yaml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/mq_bridge/py.typed +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/python/mq-bridge-py/LICENSE.python +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/python/mq-bridge-py/analysis/bench_http_native.py +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/python/mq-bridge-py/examples/bench_memory.py +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/python/mq-bridge-py/examples/bench_memory.yaml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/python/mq-bridge-py/examples/json_route.py +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/python/mq-bridge-py/examples/memory.yaml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/python/mq-bridge-py/tests/test_performance_smoke.py +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/python/mq-bridge-py/tests/test_public_api.py +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/analysis/HTTP_STREAM_ENDPOINT_PLAN.md +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/analysis/benches/metadata_bench.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/analysis/debug_ibm_mq_tls.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/analysis/http/analyze_xctrace_time_profile.py +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/analysis/http/http_flamegraph.py +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/httparena/README.md +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/techempower/Python/mq-bridge-py/README.md +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/techempower/Python/mq-bridge-py/benchmark_config.json +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/techempower/Python/mq-bridge-py/mq-bridge-py.dockerfile +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/techempower/Python/mq-bridge-py/server.py +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/techempower/README.md +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/techempower/postgres.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/techempower/seed.sql +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/techempower/verify.sh +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/the-benchmarker/README.md +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/the-benchmarker/python/mq-bridge-py/config.yaml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/the-benchmarker/python/mq-bridge-py/pyproject.toml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/scripts/the-benchmarker/python/mq-bridge-py/server.py +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/canonical_message.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/command_handler.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/amqp.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/aws.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/fanout.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/file.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/grpc.proto +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/http_stream.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/ibm_mq.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/kafka.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/memory/endpoint.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/memory/ipc_unix.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/memory/ipc_windows.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/memory/memory_transport.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/memory/mod.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/memory/transport.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/mongodb.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/mqtt.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/nats.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/null.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/reader.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/response.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/sled.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/sqlx.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/static_endpoint.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/stream_buffer.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/switch.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/endpoints/zeromq.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/errors.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/event_handler.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/event_store.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/extensions.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/lib.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/middleware/cookie_jar.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/middleware/deduplication.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/middleware/delay.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/middleware/dlq.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/middleware/limiter.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/middleware/metrics.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/middleware/random_panic.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/middleware/retry.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/middleware/weak_join.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/outcomes.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/publisher.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/response.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/route.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/traits.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/src/type_handler.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/README.md +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/armature_integration.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/amqp.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/aws.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/config.toml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/amqp.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/aws.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/ibm-mq-certs/client.crl +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/ibm-mq-certs/client.kdb +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/ibm-mq-certs/client.p12 +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/ibm-mq-certs/client.rdb +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/ibm-mq-certs/client.sth +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/ibm_mq.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/ibm_mq_tls.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/kafka-tls.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/kafka.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/mariadb.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/mongodb-replica.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/mongodb-tls.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/mongodb.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/mosquitto.conf +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/mosquitto_performance.conf +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/mosquitto_persistence.conf +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/mq_init.mqsc +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/mq_init_tls.mqsc +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/mqtt.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/mqtt_performance.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/mysql.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/nats.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/docker-compose/postgres.yml +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/file.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/grpc.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/grpc_tls.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/http.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/http_tls.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/ibm_mq.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/ibm_mq_tls.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/ipc.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/kafka.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/kafka_tls.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/logic_test.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/mariadb.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/memory.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/mod.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/mongodb.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/mongodb_raw.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/mongodb_tls.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/mqtt.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/mysql.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/nats.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/performance_static.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/postgres.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/route.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/scripts/gen_certs.sh +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/sqlite.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/tls_helpers.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration/zeromq.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/integration_test.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/ref_test.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/sqlite_test.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/tls_example.rs +0 -0
- {mq_bridge_py_basic-0.2.18 → mq_bridge_py_basic-0.2.20}/tests/unit_tests.md +0 -0
|
@@ -50,13 +50,24 @@ jobs:
|
|
|
50
50
|
runs-on: ubuntu-latest
|
|
51
51
|
needs: release
|
|
52
52
|
environment: release
|
|
53
|
+
permissions:
|
|
54
|
+
# Required for crates.io Trusted Publishing (OIDC).
|
|
55
|
+
contents: read
|
|
56
|
+
id-token: write
|
|
53
57
|
steps:
|
|
54
|
-
- uses: actions/checkout@v4
|
|
55
|
-
|
|
58
|
+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
59
|
+
with:
|
|
60
|
+
persist-credentials: false
|
|
61
|
+
|
|
56
62
|
- name: Install Rust toolchain
|
|
57
63
|
uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable
|
|
58
|
-
|
|
64
|
+
|
|
65
|
+
# Exchange the GitHub OIDC token for a short-lived crates.io token.
|
|
66
|
+
- name: Authenticate to crates.io (Trusted Publishing)
|
|
67
|
+
uses: rust-lang/crates-io-auth-action@c6f97d42243bad5fab37ca0427f495c86d5b1a18 # v1.0.5
|
|
68
|
+
id: auth
|
|
69
|
+
|
|
59
70
|
- name: Publish to crates.io
|
|
60
71
|
run: cargo publish
|
|
61
72
|
env:
|
|
62
|
-
CARGO_REGISTRY_TOKEN: ${{
|
|
73
|
+
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
|
|
@@ -299,7 +299,7 @@ dependencies = [
|
|
|
299
299
|
"tokio-rustls 0.26.4",
|
|
300
300
|
"tokio-stream",
|
|
301
301
|
"tokio-util",
|
|
302
|
-
"tokio-websockets",
|
|
302
|
+
"tokio-websockets 0.10.1",
|
|
303
303
|
"tracing",
|
|
304
304
|
"tryhard",
|
|
305
305
|
"url",
|
|
@@ -3057,9 +3057,10 @@ dependencies = [
|
|
|
3057
3057
|
|
|
3058
3058
|
[[package]]
|
|
3059
3059
|
name = "mq-bridge"
|
|
3060
|
-
version = "0.2.
|
|
3060
|
+
version = "0.2.20"
|
|
3061
3061
|
dependencies = [
|
|
3062
3062
|
"anyhow",
|
|
3063
|
+
"arc-swap",
|
|
3063
3064
|
"async-channel",
|
|
3064
3065
|
"async-nats",
|
|
3065
3066
|
"async-trait",
|
|
@@ -3108,7 +3109,7 @@ dependencies = [
|
|
|
3108
3109
|
"tokio",
|
|
3109
3110
|
"tokio-rustls 0.26.4",
|
|
3110
3111
|
"tokio-stream",
|
|
3111
|
-
"tokio-
|
|
3112
|
+
"tokio-websockets 0.13.2",
|
|
3112
3113
|
"tonic",
|
|
3113
3114
|
"tonic-prost",
|
|
3114
3115
|
"tonic-prost-build",
|
|
@@ -3123,7 +3124,7 @@ dependencies = [
|
|
|
3123
3124
|
|
|
3124
3125
|
[[package]]
|
|
3125
3126
|
name = "mq-bridge-py"
|
|
3126
|
-
version = "0.2.
|
|
3127
|
+
version = "0.2.20"
|
|
3127
3128
|
dependencies = [
|
|
3128
3129
|
"anyhow",
|
|
3129
3130
|
"async-trait",
|
|
@@ -3131,6 +3132,7 @@ dependencies = [
|
|
|
3131
3132
|
"fast-uuid-v7",
|
|
3132
3133
|
"mq-bridge",
|
|
3133
3134
|
"pyo3",
|
|
3135
|
+
"schemars",
|
|
3134
3136
|
"serde",
|
|
3135
3137
|
"serde_json",
|
|
3136
3138
|
"serde_yaml_ng",
|
|
@@ -4883,6 +4885,12 @@ dependencies = [
|
|
|
4883
4885
|
"digest 0.11.3",
|
|
4884
4886
|
]
|
|
4885
4887
|
|
|
4888
|
+
[[package]]
|
|
4889
|
+
name = "sha1_smol"
|
|
4890
|
+
version = "1.0.1"
|
|
4891
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
4892
|
+
checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d"
|
|
4893
|
+
|
|
4886
4894
|
[[package]]
|
|
4887
4895
|
name = "sha2"
|
|
4888
4896
|
version = "0.10.9"
|
|
@@ -5549,18 +5557,6 @@ dependencies = [
|
|
|
5549
5557
|
"tokio",
|
|
5550
5558
|
]
|
|
5551
5559
|
|
|
5552
|
-
[[package]]
|
|
5553
|
-
name = "tokio-tungstenite"
|
|
5554
|
-
version = "0.29.0"
|
|
5555
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
5556
|
-
checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c"
|
|
5557
|
-
dependencies = [
|
|
5558
|
-
"futures-util",
|
|
5559
|
-
"log",
|
|
5560
|
-
"tokio",
|
|
5561
|
-
"tungstenite",
|
|
5562
|
-
]
|
|
5563
|
-
|
|
5564
5560
|
[[package]]
|
|
5565
5561
|
name = "tokio-util"
|
|
5566
5562
|
version = "0.7.18"
|
|
@@ -5597,6 +5593,25 @@ dependencies = [
|
|
|
5597
5593
|
"webpki-roots 0.26.11",
|
|
5598
5594
|
]
|
|
5599
5595
|
|
|
5596
|
+
[[package]]
|
|
5597
|
+
name = "tokio-websockets"
|
|
5598
|
+
version = "0.13.2"
|
|
5599
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
5600
|
+
checksum = "dad543404f98bfc969aeb71994105c592acfc6c43323fddcd016bb208d1c65cb"
|
|
5601
|
+
dependencies = [
|
|
5602
|
+
"base64",
|
|
5603
|
+
"bytes",
|
|
5604
|
+
"fastrand",
|
|
5605
|
+
"futures-core",
|
|
5606
|
+
"futures-sink",
|
|
5607
|
+
"http 1.4.2",
|
|
5608
|
+
"httparse",
|
|
5609
|
+
"sha1_smol",
|
|
5610
|
+
"simdutf8",
|
|
5611
|
+
"tokio",
|
|
5612
|
+
"tokio-util",
|
|
5613
|
+
]
|
|
5614
|
+
|
|
5600
5615
|
[[package]]
|
|
5601
5616
|
name = "toml"
|
|
5602
5617
|
version = "1.1.2+spec-1.1.0"
|
|
@@ -5862,22 +5877,6 @@ dependencies = [
|
|
|
5862
5877
|
"tokio",
|
|
5863
5878
|
]
|
|
5864
5879
|
|
|
5865
|
-
[[package]]
|
|
5866
|
-
name = "tungstenite"
|
|
5867
|
-
version = "0.29.0"
|
|
5868
|
-
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
5869
|
-
checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8"
|
|
5870
|
-
dependencies = [
|
|
5871
|
-
"bytes",
|
|
5872
|
-
"data-encoding",
|
|
5873
|
-
"http 1.4.2",
|
|
5874
|
-
"httparse",
|
|
5875
|
-
"log",
|
|
5876
|
-
"rand 0.9.4",
|
|
5877
|
-
"sha1 0.10.6",
|
|
5878
|
-
"thiserror 2.0.18",
|
|
5879
|
-
]
|
|
5880
|
-
|
|
5881
5880
|
[[package]]
|
|
5882
5881
|
name = "typed-builder"
|
|
5883
5882
|
version = "0.22.0"
|
|
@@ -16,7 +16,7 @@ members = ["python/mq-bridge-py"]
|
|
|
16
16
|
resolver = "2"
|
|
17
17
|
|
|
18
18
|
[workspace.package]
|
|
19
|
-
version = "0.2.
|
|
19
|
+
version = "0.2.20"
|
|
20
20
|
|
|
21
21
|
[workspace.dependencies]
|
|
22
22
|
anyhow = "1.0"
|
|
@@ -26,7 +26,7 @@ fast-uuid-v7 = "0.1.5"
|
|
|
26
26
|
serde = "1.0"
|
|
27
27
|
serde_json = "1.0"
|
|
28
28
|
serde_yaml_ng = "0.10"
|
|
29
|
-
tokio = "1"
|
|
29
|
+
tokio = "1.34" # `Receiver::recv_many` (HTTP source batch drain) needs 1.34+.
|
|
30
30
|
tracing = "0.1"
|
|
31
31
|
|
|
32
32
|
[profile.release]
|
|
@@ -46,6 +46,7 @@ tokio = { workspace = true, features = ["rt-multi-thread", "macros", "sync", "ti
|
|
|
46
46
|
# Note on MSRV for optional features:
|
|
47
47
|
# The base crate keeps MSRV 1.75 with default = [].
|
|
48
48
|
# - "amqp" (lapin 4.10) requires Rust 1.88+; "http" (hyper-rustls 0.27) requires Rust 1.85+.
|
|
49
|
+
# - "websocket" (tokio-websockets 0.13) requires Rust 1.89+.
|
|
49
50
|
# - "aws" (aws-sdk-*) may require a newer stable toolchain than the base MSRV.
|
|
50
51
|
# Use `rustup override set stable` or a `rust-toolchain.toml` file when enabling these features.
|
|
51
52
|
async-trait.workspace = true
|
|
@@ -109,6 +110,7 @@ rumqttc = { version = "0.25", default-features = false, features = ["use-rustls-
|
|
|
109
110
|
mqi = { version = "0.3", optional = true }
|
|
110
111
|
|
|
111
112
|
# HTTP
|
|
113
|
+
arc-swap = { version = "1", optional = true }
|
|
112
114
|
hyper = { version = "1.8", optional = true, features = ["client", "server", "http1", "http2"] }
|
|
113
115
|
hyper-util = { version = "0.1", optional = true, features = ["tokio", "client", "client-legacy", "server", "http1", "http2"] }
|
|
114
116
|
hyper-rustls = { version = "0.27", optional = true, default-features = false, features = ["http1", "http2", "tls12", "logging", "native-tokio"] }
|
|
@@ -117,7 +119,7 @@ http-body = { version = "1.0", optional = true }
|
|
|
117
119
|
h2 = { version = "0.4", optional = true }
|
|
118
120
|
flate2 = { version = "1.0", optional = true }
|
|
119
121
|
base64 = { version = "0.22", optional = true }
|
|
120
|
-
tokio-
|
|
122
|
+
tokio-websockets = { version = "0.13", optional = true, default-features = false, features = ["client", "server", "sha1_smol", "fastrand"] }
|
|
121
123
|
|
|
122
124
|
# AWS
|
|
123
125
|
aws-config = { version = "1.8", optional = true, default-features = false, features = ["behavior-version-latest", "rt-tokio", "rustls"] }
|
|
@@ -178,8 +180,8 @@ amqp = ["lapin", "rustls", "rustls-pemfile", "url"]
|
|
|
178
180
|
nats = ["async-nats", "rustls", "rustls-pemfile"]
|
|
179
181
|
mongodb = ["dep:mongodb"]
|
|
180
182
|
mqtt = ["rumqttc", "rustls", "tokio-rustls", "rustls-pemfile", "url"]
|
|
181
|
-
http = ["hyper", "hyper-util", "hyper-rustls", "http-body-util", "dep:http-body", "rustls", "tokio-rustls", "rustls-pemfile", "webpki-roots", "h2", "dep:flate2", "dep:base64"]
|
|
182
|
-
websocket = ["dep:tokio-
|
|
183
|
+
http = ["dep:arc-swap", "hyper", "hyper-util", "hyper-rustls", "http-body-util", "dep:http-body", "rustls", "tokio-rustls", "rustls-pemfile", "webpki-roots", "h2", "dep:flate2", "dep:base64"]
|
|
184
|
+
websocket = ["dep:tokio-websockets"]
|
|
183
185
|
aws = ["aws-config", "aws-sdk-sqs", "aws-sdk-sns", "dep:base64"]
|
|
184
186
|
ibm-mq = ["mqi"]
|
|
185
187
|
zeromq = ["dep:zeromq"]
|
|
@@ -194,6 +196,8 @@ tempfile = "3.10"
|
|
|
194
196
|
chrono = "0.4"
|
|
195
197
|
metrics-util = "0.20"
|
|
196
198
|
criterion = { version = "0.8", features = ["async", "async_tokio"] }
|
|
199
|
+
# Used by the router_bench microbench to model the proposed lock-free route table.
|
|
200
|
+
arc-swap = "1"
|
|
197
201
|
mq-bridge = { path = ".", features = ["test-utils", "rustls-ring"] }
|
|
198
202
|
reqwest = { version = "0.13", features = ["stream"] }
|
|
199
203
|
|
|
@@ -207,6 +211,12 @@ name = "performance_bench"
|
|
|
207
211
|
harness = false
|
|
208
212
|
required-features = ["test-utils"]
|
|
209
213
|
|
|
214
|
+
# Isolates the per-request HTTP route lookup (Mutex<HashMap> vs ArcSwap).
|
|
215
|
+
# No external services or features required.
|
|
216
|
+
[[bench]]
|
|
217
|
+
name = "router_bench"
|
|
218
|
+
harness = false
|
|
219
|
+
|
|
210
220
|
[[test]]
|
|
211
221
|
name = "integration_test"
|
|
212
222
|
required-features = ["test-utils"]
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mq-bridge-py-basic
|
|
3
|
+
Version: 0.2.20
|
|
4
|
+
Classifier: Development Status :: 3 - Alpha
|
|
5
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Rust
|
|
13
|
+
Requires-Dist: typing-extensions>=4.0
|
|
14
|
+
License-File: LICENSE.python
|
|
15
|
+
Summary: Python bindings for mq-bridge (basic: all-platform messaging set)
|
|
16
|
+
Keywords: messaging,tokio,pyo3,maturin,mq-bridge
|
|
17
|
+
License: MIT
|
|
18
|
+
Requires-Python: >=3.9
|
|
19
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
20
|
+
Project-URL: Homepage, https://github.com/marcomq/mq-bridge
|
|
21
|
+
Project-URL: Issues, https://github.com/marcomq/mq-bridge/issues
|
|
22
|
+
Project-URL: Repository, https://github.com/marcomq/mq-bridge
|
|
23
|
+
|
|
24
|
+
# mq-bridge Python bindings
|
|
25
|
+
|
|
26
|
+
Thin Python bindings for the Rust `mq-bridge` core.
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
Pick exactly one distribution. Both install the same import path: `mq_bridge`.
|
|
31
|
+
|
|
32
|
+
| Package | Install | Includes |
|
|
33
|
+
| :--- | :--- | :--- |
|
|
34
|
+
| Full | `pip install mq-bridge-py` | Basic set plus Kafka, AWS, gRPC, MongoDB, SQLx |
|
|
35
|
+
| Basic | `pip install mq-bridge-py-basic` | HTTP, NATS, MQTT, AMQP, WebSocket, ZeroMQ, middleware |
|
|
36
|
+
|
|
37
|
+
Memory and file endpoints are always present in both packages. Use `mq-bridge-py-basic` when you want the lean all-platform wheel set. Use `mq-bridge-py` when you need Kafka or the heavier non-messaging backends.
|
|
38
|
+
|
|
39
|
+
The public API stays close to mq-bridge itself:
|
|
40
|
+
|
|
41
|
+
- `Route.from_yaml(path, name)` loads one named route from a YAML file
|
|
42
|
+
- `Route.from_yaml_str(text, name)` / `Route.from_config(mapping, name)` build a route from an in-memory YAML string or a Python `dict`, no file required
|
|
43
|
+
- `Route.with_handler(...)` attaches a raw `Message` handler, with lazy `json()`/`text()` readers and `with_json()`/`with_payload()` response helpers
|
|
44
|
+
- `Route.add_handler(kind, ...)` uses mq-bridge's `kind` dispatch and delivers decoded JSON
|
|
45
|
+
- `RetryableError` and `NonRetryableError` let Python handlers signal retry intent
|
|
46
|
+
- `Publisher.from_yaml(path, name)` (plus `from_yaml_str` / `from_config`) loads one named publisher
|
|
47
|
+
- `Publisher.send_json(...)` and `Publisher.request_json(...)` serialize Python JSON values in Rust
|
|
48
|
+
|
|
49
|
+
The Python surface is synchronous and blocking. Tokio, broker I/O, routing, and batching all stay in Rust.
|
|
50
|
+
|
|
51
|
+
## Config types and schema
|
|
52
|
+
|
|
53
|
+
`mq-bridge-app` can create and test route and endpoint JSON/YAML through its UI.
|
|
54
|
+
It does not replace your Python code or handlers, but it is useful when you want
|
|
55
|
+
a known-good connection and route shape before pasting the configuration into
|
|
56
|
+
Python. Load the generated config with `Route.from_config`, `Route.from_yaml`,
|
|
57
|
+
`Publisher.from_config`, or `Publisher.from_yaml`.
|
|
58
|
+
|
|
59
|
+
For the `from_config` / `from_yaml_str` mappings, `mq_bridge.config` ships
|
|
60
|
+
`TypedDict` definitions so editors autocomplete the config keys (`input`,
|
|
61
|
+
`output`, `batch_size`, every transport config, middleware, …):
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from mq_bridge import Route
|
|
65
|
+
from mq_bridge.config import ConfigDocument
|
|
66
|
+
|
|
67
|
+
config: ConfigDocument = {
|
|
68
|
+
"routes": {
|
|
69
|
+
"orders": {
|
|
70
|
+
"input": {"memory": {"topic": "orders.in", "capacity": 1600}},
|
|
71
|
+
"output": {"response": {}},
|
|
72
|
+
"batch_size": 128,
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
route = Route.from_config(config, "orders")
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
These types are generated from the JSON Schema, which the extension produces on
|
|
80
|
+
demand from the Rust models — there is no checked-in schema copy to drift:
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from mq_bridge import config_schema
|
|
84
|
+
|
|
85
|
+
schema = config_schema() # the JSON Schema as a dict
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`config_schema()` is handy for editor validation of YAML configs too — dump it
|
|
89
|
+
to a file and point your `# yaml-language-server: $schema=` line at it. The types
|
|
90
|
+
are regenerated with `uv run python scripts/gen_config_types.py` (a test fails if
|
|
91
|
+
they drift from the schema).
|
|
92
|
+
|
|
93
|
+
## Running a route
|
|
94
|
+
|
|
95
|
+
`Route.run()` **blocks the calling thread** until another thread calls `stop()` —
|
|
96
|
+
it deploys the route and then parks. This is convenient for a process whose only
|
|
97
|
+
job is the route, but it is a common trap: nothing after `route.run()` executes
|
|
98
|
+
until the route stops.
|
|
99
|
+
|
|
100
|
+
To keep running Python code after the route is up, use `start()` (non-blocking)
|
|
101
|
+
or the context-manager form:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
route = Route.from_config(config, "orders_route").with_handler(handle)
|
|
105
|
+
|
|
106
|
+
# Non-blocking: deploys, returns, and runs on a background thread.
|
|
107
|
+
route.start()
|
|
108
|
+
publisher.send_json({"order_id": 42}, {"kind": "order.created"})
|
|
109
|
+
route.stop()
|
|
110
|
+
route.join() # optional: wait for a clean shutdown
|
|
111
|
+
|
|
112
|
+
# Or scope it to a block — starts on enter, stops + joins on exit:
|
|
113
|
+
with Route.from_config(config, "orders_route").with_handler(handle):
|
|
114
|
+
publisher.send_json({"order_id": 42}, {"kind": "order.created"})
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Configuration/connection errors surface from `start()` itself, not from a
|
|
118
|
+
background thread. `run()` remains available for the blocking single-route case.
|
|
119
|
+
|
|
120
|
+
## Tuning (environment variables)
|
|
121
|
+
|
|
122
|
+
These knobs are read from the environment at startup:
|
|
123
|
+
|
|
124
|
+
| Variable | Default | Effect |
|
|
125
|
+
| :--- | :--- | :--- |
|
|
126
|
+
| `MQ_BRIDGE_PY_HANDLER_EXECUTOR` | `worker` | `worker` runs handlers on a dedicated interpreter thread that coalesces queued batches under one GIL acquisition (best under load); `direct` calls the handler inline. |
|
|
127
|
+
| `MQ_BRIDGE_PY_HANDLER_CONCURRENCY` | CPU count | Max in-flight handler batches. `0` disables the limit. |
|
|
128
|
+
| `MQ_BRIDGE_PY_GC_MODE` | `default` | `default` leaves CPython's cyclic GC alone; `count` disables it and runs `gc.collect()` every N messages; `off` disables it entirely (pure refcounting). |
|
|
129
|
+
| `MQ_BRIDGE_PY_GC_THRESHOLD` | `100000` | Messages between collections when `MQ_BRIDGE_PY_GC_MODE=count`. |
|
|
130
|
+
|
|
131
|
+
## Local development
|
|
132
|
+
|
|
133
|
+
`uv` is a good fit here for the Python-side developer workflow, while `maturin` stays the build backend:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
cd python/mq-bridge-py
|
|
137
|
+
uv sync --group dev --no-install-project
|
|
138
|
+
uv run maturin develop
|
|
139
|
+
uv run pytest -q
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Performance smoke tests are skipped by default because they start routes and measure
|
|
143
|
+
local throughput:
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
cd python/mq-bridge-py
|
|
147
|
+
MQ_BRIDGE_RUN_PERF_TESTS=1 uv run pytest -q -m performance
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Examples
|
|
151
|
+
|
|
152
|
+
Raw message handler:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
cd python/mq-bridge-py
|
|
156
|
+
uv run python examples/raw_route.py
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Kind-based JSON handler:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
cd python/mq-bridge-py
|
|
163
|
+
uv run python examples/json_route.py
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Memory benchmark:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
cd python/mq-bridge-py
|
|
170
|
+
uv run maturin develop --release
|
|
171
|
+
uv run python examples/bench_memory.py --messages 100000
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Analysis
|
|
175
|
+
|
|
176
|
+
HTTP comparison benchmark, driven by a native load generator (`wrk`) so the
|
|
177
|
+
client is never the bottleneck. It boots each server itself (mq-bridge in worker
|
|
178
|
+
and direct executor modes, plus FastAPI, Starlette, Sanic, aiohttp, and
|
|
179
|
+
FastStream when installed) and drives each with `wrk`:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
cd python/mq-bridge-py
|
|
183
|
+
uv run maturin develop --release
|
|
184
|
+
uv sync --group bench # optional Python HTTP peers
|
|
185
|
+
uv run python analysis/bench_http_native.py --connections 1,8,32 --duration 8
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Requires `wrk` on `PATH` (`brew install wrk`). The FastStream target compares its
|
|
189
|
+
ASGI custom-route path over Uvicorn; it is not a broker-backed subscriber/publisher
|
|
190
|
+
benchmark. The examples use included sample configs or create temporary configs.
|
|
191
|
+
|
|
@@ -157,6 +157,12 @@ The `response` output endpoint sends a reply back to the original requester. Thi
|
|
|
157
157
|
There is a separate repository for running mq-bridge as a standalone app, for example as a Docker container configured via YAML or environment variables:
|
|
158
158
|
https://github.com/marcomq/mq-bridge-app
|
|
159
159
|
|
|
160
|
+
### Configuration-first workflow
|
|
161
|
+
|
|
162
|
+
`mq-bridge-app` can be used to create and test route and endpoint configurations through a UI. The generated JSON/YAML can then be copied into an application and loaded by the Rust library or the Python bindings.
|
|
163
|
+
|
|
164
|
+
This does not replace application code or handlers, but it is useful when you want a known-good connection and route shape before pasting the configuration into code. For Python projects, routes and publishers are commonly loaded from JSON/YAML with `Route.from_config`, `Route.from_yaml`, `Publisher.from_config`, or `Publisher.from_yaml`.
|
|
165
|
+
|
|
160
166
|
### Programmatic Handlers
|
|
161
167
|
|
|
162
168
|
For business logic, `mq-bridge` provides a handler layer separate from transport-level middleware. This is where message-specific code usually belongs.
|
|
@@ -648,7 +648,7 @@ pub mod websocket_helper {
|
|
|
648
648
|
let websocket_config = WebSocketConfig {
|
|
649
649
|
url: "127.0.0.1:0".to_string(),
|
|
650
650
|
path: Some("/bench".to_string()),
|
|
651
|
-
|
|
651
|
+
routed_queue_capacity: Some(super::PERF_TEST_MESSAGE_COUNT * 2),
|
|
652
652
|
..Default::default()
|
|
653
653
|
};
|
|
654
654
|
|