mq-bridge-py-basic 0.3.8__tar.gz → 0.3.10__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.3.10/.github/dependabot.yml +11 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/.github/workflows/ci.yml +27 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/.gitignore +4 -0
- mq_bridge_py_basic-0.3.10/CHANGELOG.md +76 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/Cargo.lock +30 -10
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/Cargo.toml +16 -7
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/PKG-INFO +3 -3
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/README.md +80 -6
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/REFERENCE.md +131 -42
- mq_bridge_py_basic-0.3.10/SECURITY.md +104 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/benches/ETL_BENCHMARKS.md +5 -5
- mq_bridge_py_basic-0.3.10/deny.toml +97 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/mq-bridge.schema.json +70 -8
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/mq_bridge/__init__.pyi +8 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/mq_bridge/config.pyi +39 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/Cargo.toml +17 -2
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/README.md +2 -2
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/examples/dlt_source.py +4 -8
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/src/lib.rs +76 -9
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/tests/test_public_api.py +10 -7
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/httparena/README.md +1 -1
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/httparena/frameworks/mq-bridge-py/server.py +1 -1
- mq_bridge_py_basic-0.3.10/src/canonical_message.rs +854 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/checkpoint.rs +24 -5
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/command_handler.rs +9 -1
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/amqp.rs +20 -5
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/clickhouse.rs +4 -3
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/file/mod.rs +679 -167
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/file/tests.rs +543 -3
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/http/publisher.rs +23 -1
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/http/stream.rs +9 -5
- mq_bridge_py_basic-0.3.10/src/endpoints/kafka.rs +1927 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/memory/framed.rs +81 -13
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/mod.rs +232 -29
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/mongodb/consumer.rs +14 -9
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/mongodb/readers.rs +105 -16
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/mongodb/tests.rs +67 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/nats.rs +77 -19
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/object_store.rs +264 -47
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/postgres/mod.rs +125 -21
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/postgres/replication.rs +83 -23
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/redis_streams.rs +130 -19
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/sqlx/dedup.rs +23 -3
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/sqlx/mod.rs +413 -157
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/sqlx/tests.rs +302 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/structural/reader.rs +17 -2
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/structural/stream_buffer.rs +34 -13
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/zeromq/omq.rs +12 -3
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/zeromq/zmq.rs +25 -0
- mq_bridge_py_basic-0.3.10/src/errors.rs +172 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/lib.rs +4 -1
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/cookie_jar.rs +73 -5
- mq_bridge_py_basic-0.3.10/src/middleware/deduplication.rs +1128 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/dlq.rs +141 -2
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/encryption.rs +133 -24
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/limiter.rs +31 -1
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/mod.rs +43 -3
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/retry.rs +90 -5
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/transform/compiled.rs +133 -15
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/transform/mod.rs +7 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/transform/path.rs +26 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/transform/schema.rs +18 -6
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/transform/tests.rs +333 -7
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/models.rs +78 -5
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/route.rs +763 -7
- mq_bridge_py_basic-0.3.10/src/support/base64_engine.rs +101 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/support/compression.rs +1 -1
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/support/connection_registry.rs +3 -3
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/support/crypto.rs +3 -5
- mq_bridge_py_basic-0.3.10/src/support/crypto_envelope.rs +17 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/support/interpolation.rs +260 -17
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/support/mod.rs +3 -0
- mq_bridge_py_basic-0.3.10/src/support/source_ranges.rs +448 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/test_utils.rs +30 -1
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/traits.rs +6 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/armature_integration.rs +16 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/mariadb.rs +16 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/mod.rs +32 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/mongodb.rs +40 -1
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/mqtt.rs +9 -3
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/mysql.rs +137 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/nats.rs +48 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/object_store.rs +102 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/postgres_cdc.rs +114 -0
- mq_bridge_py_basic-0.3.10/tests/integration/redis_streams.rs +434 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/route.rs +25 -23
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration_test.rs +95 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/reference_docs_test.rs +134 -177
- mq_bridge_py_basic-0.3.8/src/canonical_message.rs +0 -471
- mq_bridge_py_basic-0.3.8/src/endpoints/kafka.rs +0 -986
- mq_bridge_py_basic-0.3.8/src/errors.rs +0 -96
- mq_bridge_py_basic-0.3.8/src/middleware/deduplication.rs +0 -582
- mq_bridge_py_basic-0.3.8/tests/integration/redis_streams.rs +0 -227
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/.github/workflows/benchmark.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/.github/workflows/ibm-mq.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/.github/workflows/node.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/.github/workflows/publish-node.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/.github/workflows/publish-python.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/.github/workflows/python.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/.github/workflows/release.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/.github/workflows/test-matrix.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/ARCHITECTURE.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/CLAUDE.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/CONFIGURATION.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/CONTRIBUTING.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/LICENSE +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/LICENSE.python +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/benches/performance_bench.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/benches/router_bench.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/benches/zeromq_backends.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/bindings-common/Cargo.toml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/bindings-common/src/lib.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/bindings-common/src/logging.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/build.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/examples/ipc_worker_queue.yaml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/mq_bridge/__init__.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/mq_bridge/config.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/mq_bridge/py.typed +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/package-lock.json +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/pyproject.toml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/LICENSE.python +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/analysis/bench_http_native.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/example.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/examples/bench_memory.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/examples/bench_memory.yaml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/examples/consume_pull.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/examples/json_route.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/examples/memory.yaml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/examples/raw_route.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/pyproject-basic.toml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/pyproject-reduced.toml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/scripts/gen_config_types.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/tests/test_config_types.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/tests/test_logging.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/tests/test_packaging.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/tests/test_performance_smoke.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/tests/test_routes.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/python/mq-bridge-py/uv.lock +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/analysis/benches/metadata_bench.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/analysis/debug_ibm_mq_tls.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/analysis/http/analyze_xctrace_time_profile.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/analysis/http/http_flamegraph.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/analysis/http/mq_bridge_http_profile.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/analysis/http/run_http_ladder.sh +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/ci/format_bench_output.sh +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/httparena/frameworks/mq-bridge-py/Dockerfile +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/httparena/frameworks/mq-bridge-py/meta.json +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/techempower/Python/mq-bridge-py/README.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/techempower/Python/mq-bridge-py/benchmark_config.json +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/techempower/Python/mq-bridge-py/mq-bridge-py.dockerfile +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/techempower/Python/mq-bridge-py/server.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/techempower/README.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/techempower/postgres.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/techempower/seed.sql +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/techempower/verify.sh +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/the-benchmarker/README.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/the-benchmarker/python/mq-bridge-py/config.yaml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/the-benchmarker/python/mq-bridge-py/pyproject.toml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/scripts/the-benchmarker/python/mq-bridge-py/server.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/aws.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/grpc.proto +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/grpc.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/http/mod.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/http/tests.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/ibm_mq.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/memory/endpoint.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/memory/ipc_unix.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/memory/ipc_windows.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/memory/memory_transport.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/memory/mod.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/memory/transport.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/mongodb/dedup.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/mongodb/mod.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/mongodb/publisher.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/mqtt.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/poll.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/postgres/VENDORED.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/postgres/pgoutput/decoder.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/postgres/pgoutput/messages.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/postgres/pgoutput/mod.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/postgres/pgoutput/registry.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/postgres/pgoutput/values.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/postgres/state.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/sled.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/structural/fanout.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/structural/mod.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/structural/null.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/structural/request.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/structural/response.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/structural/static_endpoint.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/structural/switch.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/websocket.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/zeromq/codec.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/endpoints/zeromq/mod.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/event_handler.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/event_store.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/extensions.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/buffer.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/compression.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/delay.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/metrics.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/random_panic.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/transform/coerce.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/transform/error.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/middleware/weak_join.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/outcomes.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/publisher.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/response.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/src/type_handler.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/README.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/amqp.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/aws.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/clickhouse.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/config.toml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/amqp.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/aws.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/clickhouse.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/ibm-mq-certs/client.crl +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/ibm-mq-certs/client.kdb +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/ibm-mq-certs/client.p12 +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/ibm-mq-certs/client.rdb +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/ibm-mq-certs/client.sth +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/ibm_mq.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/ibm_mq_tls.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/kafka-tls.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/kafka.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/mariadb.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/mongodb-replica.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/mongodb-tls.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/mongodb.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/mosquitto.conf +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/mosquitto_performance.conf +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/mosquitto_persistence.conf +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/mq_init.mqsc +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/mq_init_tls.mqsc +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/mqtt.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/mqtt_performance.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/mysql.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/nats.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/object_store.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/postgres.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/postgres_cdc.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/docker-compose/redis.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/file.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/grpc.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/grpc_tls.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/http.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/http_tls.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/ibm_mq.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/ibm_mq_tls.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/ipc.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/kafka.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/kafka_tls.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/logic_test.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/memory.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/mongodb_raw.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/mongodb_tls.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/performance_static.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/postgres.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/scripts/gen_certs.sh +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/sqlite.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/tls_helpers.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/websocket.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/integration/zeromq.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/memory_leak_test.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/ref_test.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/sqlite_test.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/tls_example.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/unit_tests.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.10}/tests/websocket_test.rs +0 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
|
3
|
+
# Please see the documentation for all configuration options:
|
|
4
|
+
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
5
|
+
|
|
6
|
+
version: 2
|
|
7
|
+
updates:
|
|
8
|
+
- package-ecosystem: "cargo" # See documentation for possible values
|
|
9
|
+
directory: "/" # Location of package manifests
|
|
10
|
+
schedule:
|
|
11
|
+
interval: "weekly"
|
|
@@ -305,3 +305,30 @@ jobs:
|
|
|
305
305
|
|
|
306
306
|
- name: Build documentation (deny warnings)
|
|
307
307
|
run: RUSTDOCFLAGS="-D warnings" cargo doc --all-features --no-deps
|
|
308
|
+
|
|
309
|
+
# Supply chain: licenses, banned crates, source registries, RustSec advisories
|
|
310
|
+
supply-chain:
|
|
311
|
+
name: Supply Chain
|
|
312
|
+
runs-on: ubuntu-latest
|
|
313
|
+
permissions:
|
|
314
|
+
contents: read
|
|
315
|
+
steps:
|
|
316
|
+
- uses: actions/checkout@v4
|
|
317
|
+
with:
|
|
318
|
+
persist-credentials: false
|
|
319
|
+
|
|
320
|
+
# Hard gate: an unapproved license, a banned crate or a non-crates.io
|
|
321
|
+
# source is always a real, actionable problem in this repo.
|
|
322
|
+
- name: Licenses / bans / sources
|
|
323
|
+
uses: EmbarkStudios/cargo-deny-action@v2
|
|
324
|
+
with:
|
|
325
|
+
command: check bans licenses sources
|
|
326
|
+
|
|
327
|
+
# Informational: every current advisory is in a transitive dependency we
|
|
328
|
+
# cannot upgrade ourselves, and RustSec updates daily. SECURITY.md records
|
|
329
|
+
# the per-feature reachability analysis; deny.toml carries the reasoning.
|
|
330
|
+
- name: Advisories (informational)
|
|
331
|
+
continue-on-error: true
|
|
332
|
+
uses: EmbarkStudios/cargo-deny-action@v2
|
|
333
|
+
with:
|
|
334
|
+
command: check advisories
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `mq-bridge`. Newest first.
|
|
4
|
+
|
|
5
|
+
## 0.3.10
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
|
|
10
|
+
- DLQ and output middleware now run around the publish step, not inside the handler, so a
|
|
11
|
+
handler failure is no longer retried by the output chain. The tradeoff: a handler failure
|
|
12
|
+
now skips the output middleware entirely, so `dlq` on the output endpoint cannot capture
|
|
13
|
+
it — only publish failures reach the DLQ. Put a `dlq` on the input endpoint to catch
|
|
14
|
+
handler failures.
|
|
15
|
+
- Errors carry their full cause chain instead of only the outermost context.
|
|
16
|
+
- `deduplication` on an **output** endpoint is now a startup error instead of a warning and a
|
|
17
|
+
silent no-op. Move it to the route's input endpoint.
|
|
18
|
+
- `limiter` paces a single `send_batch` by its own message count, so one large batch is no
|
|
19
|
+
longer a free burst. Sustained throughput is unchanged.
|
|
20
|
+
- A `message_id` that is neither a UUID nor a `u128` is hashed to a stable id rather than
|
|
21
|
+
making the whole JSON envelope unparseable.
|
|
22
|
+
|
|
23
|
+
### Performance
|
|
24
|
+
|
|
25
|
+
- **Kafka consumer**: a long-lived prefetch task reads librdkafka continuously into a bounded
|
|
26
|
+
channel, instead of rebuilding the stream inside every `receive_batch`. librdkafka only keeps
|
|
27
|
+
requesting records while its queue is drained, so every pause the pipeline took — a transform,
|
|
28
|
+
a slow sink — was also a pause in fetching, and the fetch rate collapsed to well under what the
|
|
29
|
+
broker could serve. Batch offsets are also recorded once per partition rather than once per
|
|
30
|
+
message, which was O(n²) in the batch and allocated two `CString`s per record.
|
|
31
|
+
Kafka → transform → file: **192,854 → 824,983 rows/s** on the 1M-row, four-partition
|
|
32
|
+
benchmark, from 0.35x to 1.51x Arroyo on identical output. A 16,384-message passthrough
|
|
33
|
+
batch went from 11.5s to 2.2s, and from 10.4s to 0.9s of CPU.
|
|
34
|
+
- **Postgres / sqlx**: `test_before_acquire(false)` on the pool, zero-copy row encoding via
|
|
35
|
+
a prebuilt `JsonRowSchema`, and prebuilt first/next page queries on the cursor path.
|
|
36
|
+
- **Command handler**: `send_batch` no longer loops per-message `send()` (≈8x on batched routes).
|
|
37
|
+
- **File**: single-pass byte-array decode, faster CSV writes, compression sniffing.
|
|
38
|
+
- **Deduplication**: the two-phase reserve/commit no longer writes to the store twice per
|
|
39
|
+
message. Reservations are held in memory — sled takes an exclusive file lock on its directory,
|
|
40
|
+
so a claim only ever has to be visible to this process — leaving one write per message, on
|
|
41
|
+
commit.
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- `insert_query` batch inserts dropped anything but a bare token from the `VALUES` tuple, so
|
|
46
|
+
`decode(${payload:x}, 'base64')` and casts were silently discarded — a binary (`bytea`)
|
|
47
|
+
column could not be written. The batch path now keeps the user's SQL and falls back to
|
|
48
|
+
iterative inserts when the tuple contains an expression.
|
|
49
|
+
- A payload string containing an embedded NUL byte was dropped by the driver and stored as
|
|
50
|
+
SQL `NULL` while the route reported success. It is now rejected as non-retryable.
|
|
51
|
+
- Database errors were rendered twice, because `sqlx` errors already display their own
|
|
52
|
+
source. Cause chains now skip a link an earlier one already contains.
|
|
53
|
+
- `cookie_jar`'s `inject_metadata` resolved only a bare stored name, so the namespaced
|
|
54
|
+
`cookie.<name>` / `value.<name>` spelling that `export_metadata_prefix` reports back
|
|
55
|
+
injected nothing. Both spellings now work.
|
|
56
|
+
- MQTT publishes are confirmed by PUBACK/PUBCOMP and guarded against session resets, which
|
|
57
|
+
took chaos-test message loss to zero.
|
|
58
|
+
- Postgres CDC advances its replication slot durably on shutdown instead of leaving the
|
|
59
|
+
feedback unflushed.
|
|
60
|
+
- `deduplication` could silently drop a message after a crash. The reservation was written to
|
|
61
|
+
the store *before* the message was processed, so a redelivery arriving within the 5s pending
|
|
62
|
+
TTL was classified as a duplicate and acked — without ever having been written to the sink.
|
|
63
|
+
Reservations are now in-memory and die with the process, so the redelivery is reprocessed.
|
|
64
|
+
- A Kafka record with no value — a tombstone, which is ordinary traffic on a compacted topic —
|
|
65
|
+
failed the whole batch. Its offset was never committed, so the route reconnected onto the same
|
|
66
|
+
record forever: one tombstone wedged the consumer permanently, and a compacted topic could not
|
|
67
|
+
be consumed at all. Tombstones now arrive as an empty payload flagged `mqb.kafka.tombstone`.
|
|
68
|
+
- `--drain` on a Kafka source could report success having copied only part of a topic, or none
|
|
69
|
+
of it. An idle wait was taken to mean "source exhausted", but an idle channel means nothing on
|
|
70
|
+
its own: before the first fetch lands, or in an ordinary gap between fetches, it looks exactly
|
|
71
|
+
the same as the end of the data. The shorter the idle timeout the more went missing — at 1ms a
|
|
72
|
+
1,000,000-row topic landed 0 rows, and the copy still exited successfully. A drain now
|
|
73
|
+
completes only once every assigned partition has reached the offset it held when the drain
|
|
74
|
+
began, and lands all 1,000,000 rows at every idle timeout including 0.
|
|
75
|
+
- Drain no longer hangs on an empty source, and reconnect attempts are bounded.
|
|
76
|
+
- CSV reader handles quoted newlines; file endpoints fail fast on an unopenable path.
|
|
@@ -2976,6 +2976,15 @@ dependencies = [
|
|
|
2976
2976
|
"windows-link",
|
|
2977
2977
|
]
|
|
2978
2978
|
|
|
2979
|
+
[[package]]
|
|
2980
|
+
name = "libmimalloc-sys"
|
|
2981
|
+
version = "0.1.49"
|
|
2982
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
2983
|
+
checksum = "6a45a52f43e1c16f667ccfe4dd8c85b7f7c204fd5e3bf46c5b0db9a5c3c0b8e9"
|
|
2984
|
+
dependencies = [
|
|
2985
|
+
"cc",
|
|
2986
|
+
]
|
|
2987
|
+
|
|
2979
2988
|
[[package]]
|
|
2980
2989
|
name = "libmqm-constants"
|
|
2981
2990
|
version = "0.8.4"
|
|
@@ -3200,6 +3209,15 @@ dependencies = [
|
|
|
3200
3209
|
"sketches-ddsketch",
|
|
3201
3210
|
]
|
|
3202
3211
|
|
|
3212
|
+
[[package]]
|
|
3213
|
+
name = "mimalloc"
|
|
3214
|
+
version = "0.1.52"
|
|
3215
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3216
|
+
checksum = "2d4139bb28d14ad1facf21d5eb8825051b326e172d216b39f6d31df53cc97862"
|
|
3217
|
+
dependencies = [
|
|
3218
|
+
"libmimalloc-sys",
|
|
3219
|
+
]
|
|
3220
|
+
|
|
3203
3221
|
[[package]]
|
|
3204
3222
|
name = "mime"
|
|
3205
3223
|
version = "0.3.17"
|
|
@@ -3330,7 +3348,7 @@ dependencies = [
|
|
|
3330
3348
|
|
|
3331
3349
|
[[package]]
|
|
3332
3350
|
name = "mq-bridge"
|
|
3333
|
-
version = "0.3.
|
|
3351
|
+
version = "0.3.10"
|
|
3334
3352
|
dependencies = [
|
|
3335
3353
|
"aes-gcm",
|
|
3336
3354
|
"anyhow",
|
|
@@ -3411,7 +3429,7 @@ dependencies = [
|
|
|
3411
3429
|
|
|
3412
3430
|
[[package]]
|
|
3413
3431
|
name = "mq-bridge-bindings-common"
|
|
3414
|
-
version = "0.3.
|
|
3432
|
+
version = "0.3.10"
|
|
3415
3433
|
dependencies = [
|
|
3416
3434
|
"anyhow",
|
|
3417
3435
|
"fast-uuid-v7",
|
|
@@ -3425,12 +3443,13 @@ dependencies = [
|
|
|
3425
3443
|
|
|
3426
3444
|
[[package]]
|
|
3427
3445
|
name = "mq-bridge-node"
|
|
3428
|
-
version = "0.3.
|
|
3446
|
+
version = "0.3.10"
|
|
3429
3447
|
dependencies = [
|
|
3430
3448
|
"anyhow",
|
|
3431
3449
|
"async-trait",
|
|
3432
3450
|
"bytes",
|
|
3433
3451
|
"fast-uuid-v7",
|
|
3452
|
+
"mimalloc",
|
|
3434
3453
|
"mq-bridge",
|
|
3435
3454
|
"mq-bridge-bindings-common",
|
|
3436
3455
|
"napi",
|
|
@@ -3446,12 +3465,13 @@ dependencies = [
|
|
|
3446
3465
|
|
|
3447
3466
|
[[package]]
|
|
3448
3467
|
name = "mq-bridge-py"
|
|
3449
|
-
version = "0.3.
|
|
3468
|
+
version = "0.3.10"
|
|
3450
3469
|
dependencies = [
|
|
3451
3470
|
"anyhow",
|
|
3452
3471
|
"async-trait",
|
|
3453
3472
|
"bytes",
|
|
3454
3473
|
"fast-uuid-v7",
|
|
3474
|
+
"mimalloc",
|
|
3455
3475
|
"mq-bridge",
|
|
3456
3476
|
"mq-bridge-bindings-common",
|
|
3457
3477
|
"pyo3",
|
|
@@ -3725,9 +3745,9 @@ dependencies = [
|
|
|
3725
3745
|
|
|
3726
3746
|
[[package]]
|
|
3727
3747
|
name = "omq-proto"
|
|
3728
|
-
version = "0.
|
|
3748
|
+
version = "0.25.0"
|
|
3729
3749
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3730
|
-
checksum = "
|
|
3750
|
+
checksum = "856d18f6b58f39153fcf0b574efe3f04362ff44d3a46829eb984c1f9ef2d121c"
|
|
3731
3751
|
dependencies = [
|
|
3732
3752
|
"bytes",
|
|
3733
3753
|
"patricia_tree",
|
|
@@ -3739,9 +3759,9 @@ dependencies = [
|
|
|
3739
3759
|
|
|
3740
3760
|
[[package]]
|
|
3741
3761
|
name = "omq-tokio"
|
|
3742
|
-
version = "0.20.
|
|
3762
|
+
version = "0.20.3"
|
|
3743
3763
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3744
|
-
checksum = "
|
|
3764
|
+
checksum = "98aaa33702e7d723de268dd9fe725f93d469afef3f1bedb14cfa7f579f61a7b7"
|
|
3745
3765
|
dependencies = [
|
|
3746
3766
|
"arc-swap",
|
|
3747
3767
|
"bytes",
|
|
@@ -7191,9 +7211,9 @@ dependencies = [
|
|
|
7191
7211
|
|
|
7192
7212
|
[[package]]
|
|
7193
7213
|
name = "yring"
|
|
7194
|
-
version = "0.3.
|
|
7214
|
+
version = "0.3.11"
|
|
7195
7215
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
7196
|
-
checksum = "
|
|
7216
|
+
checksum = "f8545becda6379f37e13fbdf5d9de464849bdd1565a995368648f11fe9d96d13"
|
|
7197
7217
|
dependencies = [
|
|
7198
7218
|
"loom",
|
|
7199
7219
|
]
|
|
@@ -16,7 +16,7 @@ members = ["bindings-common", "python/mq-bridge-py"]
|
|
|
16
16
|
resolver = "2"
|
|
17
17
|
|
|
18
18
|
[workspace.package]
|
|
19
|
-
version = "0.3.
|
|
19
|
+
version = "0.3.10"
|
|
20
20
|
|
|
21
21
|
[workspace.dependencies]
|
|
22
22
|
anyhow = "1.0"
|
|
@@ -29,6 +29,12 @@ serde_yaml_ng = "0.10"
|
|
|
29
29
|
tokio = "1.34" # `Receiver::recv_many` (HTTP source batch drain) needs 1.34+.
|
|
30
30
|
tracing = "0.1"
|
|
31
31
|
|
|
32
|
+
[profile.dev.package."*"]
|
|
33
|
+
debug = false
|
|
34
|
+
|
|
35
|
+
[profile.dev.build-override]
|
|
36
|
+
debug = false
|
|
37
|
+
|
|
32
38
|
[profile.release]
|
|
33
39
|
lto = "thin"
|
|
34
40
|
strip = "symbols"
|
|
@@ -138,7 +144,8 @@ flate2 = { version = "1.1", optional = true }
|
|
|
138
144
|
lz4_flex = { version = "0.14", optional = true, default-features = false, features = ["frame"] }
|
|
139
145
|
# zstd (bundled libzstd via zstd-sys); Decoder handles concatenated frames like gzip/lz4.
|
|
140
146
|
zstd = { version = "0.13", optional = true }
|
|
141
|
-
|
|
147
|
+
# Non-optional: `CanonicalMessage`'s JSON form encodes binary payloads as base64.
|
|
148
|
+
base64 = { version = "0.23" }
|
|
142
149
|
|
|
143
150
|
# AEAD ciphers for the `encryption` feature (payload middleware + at-rest file/object).
|
|
144
151
|
chacha20poly1305 = { version = "0.11", optional = true }
|
|
@@ -210,7 +217,7 @@ float-roundtrip = ["serde_json/float_roundtrip"]
|
|
|
210
217
|
# runtime the client is loaded lazily only when an ibm-mq endpoint is opened
|
|
211
218
|
# (clear error if the client isn't installed). Use `ibm-mq-static` instead for
|
|
212
219
|
# static linking.
|
|
213
|
-
full = ["middleware", "mongodb", "kafka", "amqp", "nats", "mqtt", "http", "aws", "zeromq", "redis-streams", "sled", "grpc", "sqlx", "clickhouse", "websocket", "postgres-cdc", "object-store", "rustls-aws-lc", "ibm-mq"]
|
|
220
|
+
full = ["middleware", "mongodb", "kafka", "amqp", "nats", "mqtt", "http", "aws", "zeromq", "zeromq-omq", "redis-streams", "sled", "grpc", "sqlx", "clickhouse", "websocket", "postgres-cdc", "object-store", "rustls-aws-lc", "ibm-mq"]
|
|
214
221
|
|
|
215
222
|
# Endpoints that build across most OS targets (glibc/musl/Alpine, macOS,
|
|
216
223
|
# Windows, aarch64/armv7) without a special toolchain — no librdkafka, protoc,
|
|
@@ -229,7 +236,7 @@ dedup = ["sled"]
|
|
|
229
236
|
compression = ["dep:flate2", "dep:lz4_flex", "dep:zstd"]
|
|
230
237
|
# AEAD payload encryption: the `encryption` middleware and the at-rest
|
|
231
238
|
# `encryption` field on the file/object_store endpoints.
|
|
232
|
-
encryption = ["dep:chacha20poly1305", "dep:aes-gcm"
|
|
239
|
+
encryption = ["dep:chacha20poly1305", "dep:aes-gcm"]
|
|
233
240
|
metrics = ["dep:metrics"]
|
|
234
241
|
test-utils = ["dep:tracing-appender", "dep:tracing-subscriber", "dep:serde_yaml_ng"]
|
|
235
242
|
# Opt-in produce/consume-only isolation benchmarks (throwaway diagnostics, off by default)
|
|
@@ -254,9 +261,9 @@ amqp = ["lapin", "rustls", "rustls-pemfile", "url"]
|
|
|
254
261
|
nats = ["async-nats", "rustls", "rustls-pemfile"]
|
|
255
262
|
mongodb = ["dep:mongodb", "url"]
|
|
256
263
|
mqtt = ["rumqttc", "rustls", "tokio-rustls", "rustls-pemfile", "url"]
|
|
257
|
-
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:lz4_flex", "dep:zstd"
|
|
264
|
+
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:lz4_flex", "dep:zstd"]
|
|
258
265
|
websocket = ["dep:tokio-websockets"]
|
|
259
|
-
aws = ["aws-config", "aws-sdk-sqs", "aws-sdk-sns"
|
|
266
|
+
aws = ["aws-config", "aws-sdk-sqs", "aws-sdk-sns"]
|
|
260
267
|
# Runtime-loaded IBM MQ client via dlopen: builds with no SDK present; the IBM
|
|
261
268
|
# redistributable client is only needed at runtime, and only if an ibm-mq
|
|
262
269
|
# endpoint is actually used.
|
|
@@ -283,10 +290,12 @@ object-store = ["dep:object_store", "url"]
|
|
|
283
290
|
# Postgres logical-replication CDC (pgoutput). Reuses the sqlx dependency for the
|
|
284
291
|
# slot-lifecycle control plane; the streaming wire protocol is pgwire-replication.
|
|
285
292
|
# Needs Rust 1.88 (pgwire-replication MSRV), like the amqp feature gate.
|
|
286
|
-
postgres-cdc = ["dep:pgwire-replication", "dep:byteorder", "sqlx", "
|
|
293
|
+
postgres-cdc = ["dep:pgwire-replication", "dep:byteorder", "sqlx", "url", "dep:percent-encoding"]
|
|
287
294
|
|
|
288
295
|
[dev-dependencies]
|
|
289
296
|
config = { version = "0.15" }
|
|
297
|
+
# `start_paused` — lets a test cross a 30s health window without waiting 30s.
|
|
298
|
+
tokio = { workspace = true, features = ["test-util"] }
|
|
290
299
|
serde_yaml_ng = "0.10"
|
|
291
300
|
tempfile = "3.27"
|
|
292
301
|
chrono = "0.4"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mq-bridge-py-basic
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.10
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: License :: OSI Approved :: MIT License
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -232,8 +232,8 @@ that ack each batch individually (NATS JetStream, AMQP, MQTT) accept any order.
|
|
|
232
232
|
> per source position (Kafka `partition:offset`, NATS `stream_sequence`, AMQP
|
|
233
233
|
> delivery tag) and makes a natural primary key. Source cursor fields are also
|
|
234
234
|
> available in `message.metadata` (`mqb.src.kafka_topic`/`mqb.src.kafka_offset`, `mqb.src.nats_subject`/`mqb.src.nats_stream_sequence`,
|
|
235
|
-
> `mqb.src.amqp_routing_key`/`mqb.src.amqp_delivery_tag`) when
|
|
236
|
-
>
|
|
235
|
+
> `mqb.src.amqp_routing_key`/`mqb.src.amqp_delivery_tag`) when its Kafka, NATS, or
|
|
236
|
+
> AMQP source config sets `source_metadata: true` (off by default).
|
|
237
237
|
>
|
|
238
238
|
> **Ack deadlines vs slow loads.** JetStream `AckWait` (default 30s), AMQP
|
|
239
239
|
> prefetch/consumer-timeout and MQTT inflight windows each bound how long a batch
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|

|
|
7
7
|

|
|
8
8
|

|
|
9
|
+
[](deny.toml)
|
|
10
|
+
[](SECURITY.md)
|
|
9
11
|
[](LICENSE)
|
|
10
12
|
|
|
11
13
|
|
|
@@ -21,7 +23,7 @@ It is not only a forwarder. A route can transform, filter, fan out, retry, rate-
|
|
|
21
23
|
|
|
22
24
|
## Move data from A to B — inside your own service
|
|
23
25
|
|
|
24
|
-
If you need to move data reliably between systems and you write code (Rust, Python, or Node), `mq-bridge` is a strong default. It is a **library you embed**, not a daemon or control plane you operate.
|
|
26
|
+
If you need to move data or events reliably between systems and you write code (Rust, Python, or Node), `mq-bridge` is a strong default. It is a **library you embed**, not a daemon or control plane you operate.
|
|
25
27
|
|
|
26
28
|
**Prefer not to write code?** [`mq-bridge-app`](https://github.com/marcomq/mq-bridge-app) runs the exact same engine as a **standalone, zero-code ETL service** configured entirely by **YAML or environment variables** — move data from A to B without writing a line. It ships a **Postman-style UI** to build, send, and inspect messages against a route, and can **import Postman collections and AsyncAPI documents** to scaffold routes and endpoints for you.
|
|
27
29
|
|
|
@@ -33,7 +35,9 @@ If you need to move data reliably between systems and you write code (Rust, Pyth
|
|
|
33
35
|
* **TLS everywhere, one config shape**: a single `TlsConfig` block (CA bundle, client cert/key for mTLS, insecure-skip) is reused across transports.
|
|
34
36
|
* **Self-hosted, no daemon**: generate config in the optional UI, paste it into your code, run it in-process. No hosted control plane, no separate scheduler.
|
|
35
37
|
|
|
36
|
-
> **Throughput & footprint.** In our own benchmarks, the same engine — driven the zero-code way through [`mq-bridge-app`](https://github.com/marcomq/mq-bridge-app) —
|
|
38
|
+
> **Throughput & footprint.** In our own benchmarks, the same engine — driven the zero-code way through [`mq-bridge-app`](https://github.com/marcomq/mq-bridge-app) — on a CSV→JSONL file conversion (1,000,000 mixed-type rows, ~116 MiB) sustained **1,133,786 rows/s** at ~22 MiB, about **~58x faster** and **~20x leaner in memory** than Meltano (`tap-csv` → `target-jsonl`, ~19,500 rows/s / ~444 MiB). Full setup, methodology, and the exact parameters are in [`benches/ETL_BENCHMARKS.md`](benches/ETL_BENCHMARKS.md).
|
|
39
|
+
|
|
40
|
+
> **Kafka → file.** In a 1,000,000-row relay with the default file format and no transform, the engine was up to **80% faster than Sea Streamer**. The [`mq-bridge-app` benchmark](https://github.com/marcomq/mq-bridge-app/tree/dev/benches/etl) contains the reproducible helper and native file-format caveats.
|
|
37
41
|
|
|
38
42
|
|
|
39
43
|
## Language Bindings
|
|
@@ -306,9 +310,14 @@ server-side (default one-hour window) — `insert_deduplication_token` lets you
|
|
|
306
310
|
mq-bridge does not set one, so rely on `ReplacingMergeTree` for logical dedup and treat block-level
|
|
307
311
|
dedup only as retry-safety.
|
|
308
312
|
|
|
309
|
-
**Postgres CDC — deterministic id + `postgres.key`.** The `postgres_cdc` source
|
|
310
|
-
durable
|
|
311
|
-
|
|
313
|
+
**Postgres CDC — deterministic id + `postgres.key`.** The `postgres_cdc` source resumes from the slot's
|
|
314
|
+
durable `confirmed_flush_lsn`. In-band standby feedback is asynchronous and is *not* flushed when the
|
|
315
|
+
stream stops, so the last acks are made durable by the consumer's `Drop`, which stops the stream and
|
|
316
|
+
advances the slot synchronously. Re-delivery is therefore avoided only on a restart that actually runs
|
|
317
|
+
that teardown — a host process that exits without dropping the route (or one on a current-thread Tokio
|
|
318
|
+
runtime, where the blocking advance is skipped) replays everything since the last asynchronous feedback
|
|
319
|
+
tick. Set `checkpoint_store` to a `file://` path for a second, per-ack durable position that survives
|
|
320
|
+
teardown regardless. Treat the source as at-least-once and make the sink idempotent. Each change event
|
|
312
321
|
carries the full row (so the primary key is in the payload), `postgres.lsn` (a monotonic version),
|
|
313
322
|
`postgres.operation`/`schema`/`table`, and — when the table has a primary key / replica identity —
|
|
314
323
|
`postgres.key` (the key value). The event's `message_id` is a stable hash of `schema.table + key +
|
|
@@ -359,11 +368,56 @@ orders_upsert_branch:
|
|
|
359
368
|
duplicate to detect. Left unwrapped by `request`, the tagged message is returned as the route's
|
|
360
369
|
response as usual.
|
|
361
370
|
|
|
371
|
+
**Files & object storage — `idempotency`.** A filesystem has no unique constraint, so the `file` and
|
|
372
|
+
`object_store` sinks get replay safety a different way: **deterministic names plus covered-range
|
|
373
|
+
recovery**. Set `idempotency: true` and the sink stops writing UUID-named objects. Instead it groups
|
|
374
|
+
each batch into runs of consecutive source positions and writes one immutable part per run, named
|
|
375
|
+
for the range it covers:
|
|
376
|
+
|
|
377
|
+
```yaml
|
|
378
|
+
kafka_to_s3:
|
|
379
|
+
input:
|
|
380
|
+
kafka: { topic: "orders", url: "localhost:9092", source_metadata: true }
|
|
381
|
+
output:
|
|
382
|
+
object_store:
|
|
383
|
+
url: "s3://my-bucket/orders"
|
|
384
|
+
idempotency: true # → s3://my-bucket/orders/part-orders-0-0-1023.jsonl
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
On startup the sink lists what is already there, parses the ranges out of the part names, and drops
|
|
388
|
+
any incoming record whose position falls inside one. Filtering is **per record, not per batch**, so
|
|
389
|
+
batch boundaries are free to differ across restarts — that is what makes it work without a
|
|
390
|
+
checkpoint protocol. Local files stage to a temp name, `fsync`, then `rename` (atomic within a
|
|
391
|
+
filesystem); object stores have no atomic rename, so a single PUT under the final name *is* the
|
|
392
|
+
commit.
|
|
393
|
+
|
|
394
|
+
This needs a replayable source position, which today means **Kafka** (topic/partition/offset) or
|
|
395
|
+
**`postgres_cdc`** (commit LSN plus in-transaction ordinal). A route with an idempotent output turns
|
|
396
|
+
`source_metadata` on for its input automatically; set it explicitly only when you want the
|
|
397
|
+
`mqb.src.*` keys for something else. Any other input is rejected when the route starts. NATS, AMQP
|
|
398
|
+
and MongoDB CDC also accept `source_metadata` and emit provenance keys, but a subject or routing key
|
|
399
|
+
is not a replayable offset, so they cannot drive an idempotent sink.
|
|
400
|
+
|
|
401
|
+
For the `file` sink, `idempotency: true` changes what `path` means: it is the directory that receives
|
|
402
|
+
the part files, not the file that is appended to. The sink creates it on startup, so pointing it at an
|
|
403
|
+
existing regular file fails there with "Failed to create idempotent file sink directory".
|
|
404
|
+
|
|
405
|
+
`compression` and `encryption` work as usual.
|
|
406
|
+
|
|
407
|
+
Current limits, all of which the sink rejects or logs rather than silently mishandling:
|
|
408
|
+
|
|
409
|
+
* No `csv` (each part would need its own header row).
|
|
410
|
+
* `date_partition` is ignored — parts are written flat under the prefix, since the name already
|
|
411
|
+
carries the range. Logged at startup.
|
|
412
|
+
* **One part file per contiguous run per batch.** There is no size-based rolling yet, so a large
|
|
413
|
+
backfill produces many small files (~1000 per 1M rows at `batch_size: 1024`). For `postgres_cdc`
|
|
414
|
+
this is per-transaction, so a high-commit-rate stream produces one small file per commit. Rolling
|
|
415
|
+
would require buffering across batches the route has already acked, which is not safe today.
|
|
362
416
|
|
|
363
417
|
### Cloud Object Storage (S3 / GCS / Azure)
|
|
364
418
|
The `object_store` endpoint (alias `s3`) reads and writes cloud object stores — Amazon S3, Google Cloud Storage, Azure Blob, Cloudflare R2, and anything else the [`object_store`](https://crates.io/crates/object_store) crate speaks — behind the same `receive_batch` / `send_batch` API. Enable it with the `object-store` feature. Credentials and backend options are read from the process environment (`AWS_ACCESS_KEY_ID`, `AWS_ENDPOINT`, `AWS_REGION`, `GOOGLE_SERVICE_ACCOUNT`, `AZURE_STORAGE_ACCOUNT`, ...); the URL scheme picks the backend (`s3://`, `gs://`, `az://`).
|
|
365
419
|
|
|
366
|
-
* **As a sink**, each flushed batch is encoded with the same file endpoint formats (`normal` JSONL, `json`, `text`, `raw`) and written as **one immutable object** at `<prefix>/[YYYY/MM/DD/]<uuidv7>.<ext>`. Objects are write-once — nothing is appended or mutated. The uuidv7 name already sorts by write time; the optional `date_partition` prefix (on by default, derived from that same id's timestamp) is a readability / lifecycle-rule convenience.
|
|
420
|
+
* **As a sink**, each flushed batch is encoded with the same file endpoint formats (`normal` JSONL, `json`, `text`, `raw`) and written as **one immutable object** at `<prefix>/[YYYY/MM/DD/]<uuidv7>.<ext>`. Objects are write-once — nothing is appended or mutated. The uuidv7 name already sorts by write time; the optional `date_partition` prefix (on by default, derived from that same id's timestamp) is a readability / lifecycle-rule convenience. This naming applies only while `idempotency` is off — with `idempotency: true` the parts are instead named for the source range they cover and written flat under the prefix, and `date_partition` is ignored (see "Files & object storage — `idempotency`" above).
|
|
367
421
|
* **As a source**, objects under the prefix are listed in key order, fetched whole, split on the delimiter, and emitted. Progress is a durable cursor holding the last fully-acked object key: set `cursor_id` and an external `checkpoint_store` (`file://`, `s3://`, `postgres://`, `mongodb://`) so a restart resumes without re-emitting. Objects are **never deleted or rewritten** — resume is non-destructive and at-least-once at object granularity (a nacked batch is redelivered; the cursor only advances once an object is fully acked). `csv` is supported on the source only.
|
|
368
422
|
|
|
369
423
|
```yaml
|
|
@@ -391,6 +445,26 @@ replay_from_s3:
|
|
|
391
445
|
> always write the `{message_id, payload, metadata}` wrapper, so the message id survives the round
|
|
392
446
|
> trip. Use `format: raw` to write payloads verbatim (bare documents, no wrapper). Applies to both
|
|
393
447
|
> `file` and `object_store`.
|
|
448
|
+
>
|
|
449
|
+
> A **source** on those formats expects that same wrapper, `message_id` included. A line that is
|
|
450
|
+
> valid JSON but not the wrapper — a hand-written fixture with only `payload` and `metadata`, say —
|
|
451
|
+
> is not decomposed: the whole line becomes the payload and the line's own `metadata` is discarded.
|
|
452
|
+
> The reader logs a warning naming the wrapper when this happens. For plain JSON lines, use
|
|
453
|
+
> `format: raw`.
|
|
454
|
+
>
|
|
455
|
+
> **Payload encoding in the wrapper.** A UTF-8 payload is written as a plain JSON string under
|
|
456
|
+
> `payload`. A binary one (compressed, encrypted, Protobuf, …) is base64-encoded under a separate
|
|
457
|
+
> `payload_base64` field; the two are mutually exclusive, as in the
|
|
458
|
+
> [CloudEvents JSON format](https://github.com/cloudevents/spec/blob/main/cloudevents/formats/json-format.md).
|
|
459
|
+
>
|
|
460
|
+
> ```json
|
|
461
|
+
> {"message_id":"019f9b12-d786-7ebe-a7ec-a1aa71bc47ae","payload":"{\"order_id\":7}"}
|
|
462
|
+
> {"message_id":"019f9b12-d78a-7c01-b0f4-2f0f4d6a1c33","payload_base64":"KLUv/SBOAQAA"}
|
|
463
|
+
> ```
|
|
464
|
+
>
|
|
465
|
+
> Sources still read the older byte-array form (`"payload":[123,34,…]`), so existing files keep
|
|
466
|
+
> working. Only the reverse is a break: a **binary** record written by this version is not readable
|
|
467
|
+
> by an older mq-bridge. Text records are compatible in both directions.
|
|
394
468
|
|
|
395
469
|
### Response Endpoint
|
|
396
470
|
The `response` output endpoint sends a reply back to the original requester. This is useful for synchronous request-reply flows, for example HTTP-to-NATS-to-HTTP. Use `response: {}` as the output endpoint configuration.
|