mq-bridge-py-basic 0.3.8__tar.gz → 0.3.9__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.8 → mq_bridge_py_basic-0.3.9}/.gitignore +4 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/Cargo.lock +30 -10
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/Cargo.toml +2 -2
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/PKG-INFO +1 -1
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/README.md +9 -4
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/REFERENCE.md +70 -34
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/benches/ETL_BENCHMARKS.md +5 -5
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/mq-bridge.schema.json +20 -5
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/mq_bridge/config.pyi +30 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/Cargo.toml +17 -2
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/src/lib.rs +70 -9
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/httparena/README.md +1 -1
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/httparena/frameworks/mq-bridge-py/server.py +1 -1
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/checkpoint.rs +24 -5
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/clickhouse.rs +4 -3
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/file/mod.rs +222 -57
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/file/tests.rs +275 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/http/publisher.rs +23 -1
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/http/stream.rs +9 -5
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/memory/framed.rs +81 -13
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/mod.rs +3 -2
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/mongodb/consumer.rs +14 -9
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/mongodb/readers.rs +24 -13
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/nats.rs +33 -2
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/object_store.rs +31 -24
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/mod.rs +69 -21
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/replication.rs +83 -23
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/redis_streams.rs +130 -19
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/sqlx/dedup.rs +23 -3
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/sqlx/mod.rs +160 -40
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/sqlx/tests.rs +40 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/reader.rs +17 -2
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/stream_buffer.rs +34 -13
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/zeromq/omq.rs +12 -3
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/zeromq/zmq.rs +25 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/errors.rs +18 -2
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/lib.rs +4 -1
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/deduplication.rs +187 -14
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/dlq.rs +141 -2
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/encryption.rs +133 -24
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/retry.rs +90 -5
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/transform/schema.rs +3 -5
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/models.rs +32 -3
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/route.rs +34 -2
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/support/compression.rs +1 -1
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/support/connection_registry.rs +3 -3
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/support/crypto.rs +3 -5
- mq_bridge_py_basic-0.3.9/src/support/crypto_envelope.rs +17 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/support/mod.rs +1 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/traits.rs +6 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/mariadb.rs +16 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/mod.rs +32 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/mongodb.rs +40 -1
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/mysql.rs +137 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/nats.rs +48 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/object_store.rs +102 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/postgres_cdc.rs +113 -0
- mq_bridge_py_basic-0.3.9/tests/integration/redis_streams.rs +434 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration_test.rs +95 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/reference_docs_test.rs +134 -177
- 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.9}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/.github/workflows/benchmark.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/.github/workflows/ci.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/.github/workflows/ibm-mq.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/.github/workflows/node.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/.github/workflows/publish-node.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/.github/workflows/publish-python.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/.github/workflows/python.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/.github/workflows/release.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/.github/workflows/test-matrix.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/ARCHITECTURE.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/CLAUDE.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/CONFIGURATION.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/CONTRIBUTING.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/LICENSE +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/LICENSE.python +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/benches/performance_bench.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/benches/router_bench.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/benches/zeromq_backends.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/bindings-common/Cargo.toml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/bindings-common/src/lib.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/bindings-common/src/logging.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/build.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/examples/ipc_worker_queue.yaml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/mq_bridge/__init__.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/mq_bridge/__init__.pyi +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/mq_bridge/config.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/mq_bridge/py.typed +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/package-lock.json +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/pyproject.toml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/LICENSE.python +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/README.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/analysis/bench_http_native.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/example.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/examples/bench_memory.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/examples/bench_memory.yaml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/examples/consume_pull.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/examples/dlt_source.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/examples/json_route.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/examples/memory.yaml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/examples/raw_route.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/pyproject-basic.toml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/pyproject-reduced.toml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/scripts/gen_config_types.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/tests/test_config_types.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/tests/test_logging.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/tests/test_packaging.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/tests/test_performance_smoke.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/tests/test_public_api.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/tests/test_routes.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/python/mq-bridge-py/uv.lock +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/analysis/benches/metadata_bench.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/analysis/debug_ibm_mq_tls.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/analysis/http/analyze_xctrace_time_profile.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/analysis/http/http_flamegraph.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/analysis/http/mq_bridge_http_profile.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/analysis/http/run_http_ladder.sh +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/ci/format_bench_output.sh +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/httparena/frameworks/mq-bridge-py/Dockerfile +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/httparena/frameworks/mq-bridge-py/meta.json +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/techempower/Python/mq-bridge-py/README.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/techempower/Python/mq-bridge-py/benchmark_config.json +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/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.9}/scripts/techempower/Python/mq-bridge-py/server.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/techempower/README.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/techempower/postgres.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/techempower/seed.sql +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/techempower/verify.sh +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/the-benchmarker/README.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/the-benchmarker/python/mq-bridge-py/config.yaml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/the-benchmarker/python/mq-bridge-py/pyproject.toml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/scripts/the-benchmarker/python/mq-bridge-py/server.py +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/canonical_message.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/command_handler.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/amqp.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/aws.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/grpc.proto +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/grpc.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/http/mod.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/http/tests.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/ibm_mq.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/kafka.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/memory/endpoint.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/memory/ipc_unix.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/memory/ipc_windows.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/memory/memory_transport.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/memory/mod.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/memory/transport.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/mongodb/dedup.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/mongodb/mod.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/mongodb/publisher.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/mongodb/tests.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/mqtt.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/poll.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/VENDORED.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/pgoutput/decoder.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/pgoutput/messages.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/pgoutput/mod.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/pgoutput/registry.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/pgoutput/values.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/postgres/state.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/sled.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/fanout.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/mod.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/null.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/request.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/response.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/static_endpoint.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/structural/switch.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/websocket.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/zeromq/codec.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/endpoints/zeromq/mod.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/event_handler.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/event_store.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/extensions.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/buffer.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/compression.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/cookie_jar.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/delay.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/limiter.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/metrics.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/mod.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/random_panic.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/transform/coerce.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/transform/compiled.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/transform/error.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/transform/mod.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/transform/path.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/transform/tests.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/middleware/weak_join.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/outcomes.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/publisher.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/response.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/support/interpolation.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/test_utils.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/src/type_handler.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/README.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/armature_integration.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/amqp.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/aws.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/clickhouse.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/config.toml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/amqp.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/aws.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/clickhouse.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/ibm-mq-certs/client.crl +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/ibm-mq-certs/client.kdb +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/ibm-mq-certs/client.p12 +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/ibm-mq-certs/client.rdb +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/ibm-mq-certs/client.sth +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/ibm_mq.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/ibm_mq_tls.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/kafka-tls.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/kafka.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mariadb.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mongodb-replica.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mongodb-tls.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mongodb.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mosquitto.conf +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mosquitto_performance.conf +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mosquitto_persistence.conf +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mq_init.mqsc +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mq_init_tls.mqsc +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mqtt.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mqtt_performance.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/mysql.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/nats.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/object_store.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/postgres.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/postgres_cdc.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/docker-compose/redis.yml +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/file.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/grpc.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/grpc_tls.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/http.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/http_tls.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/ibm_mq.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/ibm_mq_tls.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/ipc.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/kafka.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/kafka_tls.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/logic_test.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/memory.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/mongodb_raw.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/mongodb_tls.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/mqtt.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/performance_static.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/postgres.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/route.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/scripts/gen_certs.sh +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/sqlite.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/tls_helpers.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/websocket.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/integration/zeromq.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/memory_leak_test.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/ref_test.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/sqlite_test.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/tls_example.rs +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/unit_tests.md +0 -0
- {mq_bridge_py_basic-0.3.8 → mq_bridge_py_basic-0.3.9}/tests/websocket_test.rs +0 -0
|
@@ -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.9"
|
|
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.9"
|
|
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.9"
|
|
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.9"
|
|
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.9"
|
|
20
20
|
|
|
21
21
|
[workspace.dependencies]
|
|
22
22
|
anyhow = "1.0"
|
|
@@ -210,7 +210,7 @@ float-roundtrip = ["serde_json/float_roundtrip"]
|
|
|
210
210
|
# runtime the client is loaded lazily only when an ibm-mq endpoint is opened
|
|
211
211
|
# (clear error if the client isn't installed). Use `ibm-mq-static` instead for
|
|
212
212
|
# 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"]
|
|
213
|
+
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
214
|
|
|
215
215
|
# Endpoints that build across most OS targets (glibc/musl/Alpine, macOS,
|
|
216
216
|
# Windows, aarch64/armv7) without a special toolchain — no librdkafka, protoc,
|
|
@@ -33,7 +33,7 @@ If you need to move data reliably between systems and you write code (Rust, Pyth
|
|
|
33
33
|
* **TLS everywhere, one config shape**: a single `TlsConfig` block (CA bundle, client cert/key for mTLS, insecure-skip) is reused across transports.
|
|
34
34
|
* **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
35
|
|
|
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) —
|
|
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) — 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).
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
## Language Bindings
|
|
@@ -306,9 +306,14 @@ server-side (default one-hour window) — `insert_deduplication_token` lets you
|
|
|
306
306
|
mq-bridge does not set one, so rely on `ReplacingMergeTree` for logical dedup and treat block-level
|
|
307
307
|
dedup only as retry-safety.
|
|
308
308
|
|
|
309
|
-
**Postgres CDC — deterministic id + `postgres.key`.** The `postgres_cdc` source
|
|
310
|
-
durable
|
|
311
|
-
|
|
309
|
+
**Postgres CDC — deterministic id + `postgres.key`.** The `postgres_cdc` source resumes from the slot's
|
|
310
|
+
durable `confirmed_flush_lsn`. In-band standby feedback is asynchronous and is *not* flushed when the
|
|
311
|
+
stream stops, so the last acks are made durable by the consumer's `Drop`, which stops the stream and
|
|
312
|
+
advances the slot synchronously. Re-delivery is therefore avoided only on a restart that actually runs
|
|
313
|
+
that teardown — a host process that exits without dropping the route (or one on a current-thread Tokio
|
|
314
|
+
runtime, where the blocking advance is skipped) replays everything since the last asynchronous feedback
|
|
315
|
+
tick. Set `checkpoint_store` to a `file://` path for a second, per-ack durable position that survives
|
|
316
|
+
teardown regardless. Treat the source as at-least-once and make the sink idempotent. Each change event
|
|
312
317
|
carries the full row (so the primary key is in the payload), `postgres.lsn` (a monotonic version),
|
|
313
318
|
`postgres.operation`/`schema`/`table`, and — when the table has a primary key / replica identity —
|
|
314
319
|
`postgres.key` (the key value). The event's `message_id` is a stable hash of `schema.table + key +
|
|
@@ -17,7 +17,7 @@ endpoints, shape routing, or terminate a request. Data endpoints (`kafka`, `nats
|
|
|
17
17
|
Middleware attaches to an endpoint via a `middlewares:` list, on the **input**, the
|
|
18
18
|
**output**, or both:
|
|
19
19
|
|
|
20
|
-
```yaml
|
|
20
|
+
```yaml route
|
|
21
21
|
my_route:
|
|
22
22
|
input:
|
|
23
23
|
middlewares:
|
|
@@ -38,6 +38,11 @@ layer and sees the failures of the ones before it.** Put `dlq` last.
|
|
|
38
38
|
**Input (consumer) middlewares are applied in reverse, so the *first* entry is outermost**
|
|
39
39
|
and runs first on an incoming message.
|
|
40
40
|
|
|
41
|
+
**Consequence: a route that reads back what another route wrote needs the *reversed* list.**
|
|
42
|
+
Writing with `[compression, encryption]` produces `compress(encrypt(payload))`; a reader
|
|
43
|
+
given that same list would try to decrypt first and fail. The reading route must say
|
|
44
|
+
`[encryption, compression]`. The lists mirror — they are not copied.
|
|
45
|
+
|
|
41
46
|
> This is asserted by `route::tests::test_dlq_and_retry_batch_integration`,
|
|
42
47
|
> `middleware::transform::tests::test_rejected_message_reaches_the_dlq_through_the_config_wiring`,
|
|
43
48
|
> and `reference_docs_test::publisher_middleware_wraps_last_entry_outermost`, and is
|
|
@@ -58,7 +63,7 @@ middlewares:
|
|
|
58
63
|
| [`retry`](#retry) | – | ✅ | – | Exponential-backoff retry of failed sends |
|
|
59
64
|
| [`dlq`](#dlq) | – | ✅ | – | Route permanently-failed messages to another endpoint |
|
|
60
65
|
| [`transform`](#transform) | ✅ | ✅ | – | Declarative JSON mapping, coercion, validation |
|
|
61
|
-
| [`deduplication`](#deduplication) | ✅ | – | `dedup` | Drop repeated
|
|
66
|
+
| [`deduplication`](#deduplication) | ✅ | – | `dedup` | Drop repeated keys within a TTL |
|
|
62
67
|
| [`weak_join`](#weak_join) | ✅ | – | – | Correlate and join related messages |
|
|
63
68
|
| [`buffer`](#buffer) | ✅ | ✅ | – | Coalesce single sends into batches |
|
|
64
69
|
| [`limiter`](#limiter) | ✅ | ✅ | – | Cap throughput to a message rate |
|
|
@@ -103,7 +108,7 @@ Retries failed sends with exponential backoff. Output only.
|
|
|
103
108
|
| `max_interval_ms` | integer | `5000` |
|
|
104
109
|
| `multiplier` | float | `2.0` |
|
|
105
110
|
|
|
106
|
-
```yaml
|
|
111
|
+
```yaml middleware
|
|
107
112
|
- retry: { max_attempts: 5, initial_interval_ms: 200, max_interval_ms: 10000, multiplier: 2.0 }
|
|
108
113
|
```
|
|
109
114
|
|
|
@@ -119,7 +124,7 @@ Sends permanently-failed messages to a separate endpoint instead of failing the
|
|
|
119
124
|
|---|---|---|
|
|
120
125
|
| `endpoint` | Endpoint | yes |
|
|
121
126
|
|
|
122
|
-
```yaml
|
|
127
|
+
```yaml middleware
|
|
123
128
|
- dlq:
|
|
124
129
|
endpoint:
|
|
125
130
|
file: { path: "dead-letters.jsonl" }
|
|
@@ -161,7 +166,7 @@ validation — over a single parse. Input and output.
|
|
|
161
166
|
`schema` and `schema_file` are mutually exclusive. A mapping rule is either a bare path
|
|
162
167
|
string or `{ path, default, required }`.
|
|
163
168
|
|
|
164
|
-
```yaml
|
|
169
|
+
```yaml middleware
|
|
165
170
|
- transform:
|
|
166
171
|
mapping:
|
|
167
172
|
firstName: "$.first_name"
|
|
@@ -185,7 +190,7 @@ lossless ones: `string → integer`, `string → number`, `string → boolean` (
|
|
|
185
190
|
A field carrying a JSON document as a string is decoded by `contentMediaType`, following
|
|
186
191
|
JSON Schema 2020-12:
|
|
187
192
|
|
|
188
|
-
```yaml
|
|
193
|
+
```yaml middleware
|
|
189
194
|
- transform:
|
|
190
195
|
schema:
|
|
191
196
|
type: object
|
|
@@ -227,7 +232,7 @@ with neither stage configured leaves the payload untouched without parsing it.
|
|
|
227
232
|
|
|
228
233
|
### `deduplication`
|
|
229
234
|
|
|
230
|
-
Drops messages whose
|
|
235
|
+
Drops messages whose key was already seen within the TTL. Input only. Requires the `dedup`
|
|
231
236
|
feature (pulls `sled`).
|
|
232
237
|
|
|
233
238
|
| Field | Type | Required |
|
|
@@ -235,13 +240,22 @@ feature (pulls `sled`).
|
|
|
235
240
|
| `store` | string | one of `store`/`sled_path` |
|
|
236
241
|
| `sled_path` | string | one of `store`/`sled_path` |
|
|
237
242
|
| `ttl_seconds` | integer | yes |
|
|
243
|
+
| `key` | string | no (defaults to `message_id`) |
|
|
244
|
+
|
|
245
|
+
`key` is an interpolation template (see `${namespace:selector}`), typically
|
|
246
|
+
`"${payload:order_id}"`. Without it the key is the `message_id`, which most sources
|
|
247
|
+
regenerate on every read — so re-reading the same source deduplicates nothing and only
|
|
248
|
+
in-flight redeliveries are suppressed. Set `key` to a business key whenever you need
|
|
249
|
+
dedup to survive a re-read.
|
|
238
250
|
|
|
239
251
|
`store` selects the backend by URL scheme:
|
|
240
252
|
|
|
241
253
|
- `sled:///path` (or a bare path) — a local sled database; per-process, not cluster-wide.
|
|
242
254
|
- `mongodb://host/db[/collection]` — a shared collection, so multiple instances of a route
|
|
243
|
-
deduplicate against one another. Requires the `mongodb` feature.
|
|
244
|
-
|
|
255
|
+
deduplicate against one another. Requires the `mongodb` feature. Expiry is judged on read,
|
|
256
|
+
so a `ttl_seconds` boundary is honoured exactly; the TTL index only reclaims space
|
|
257
|
+
afterwards (MongoDB's sweep can lag by up to a minute). The collection defaults to
|
|
258
|
+
`mqb_dedup_<route>`. Point it at the same
|
|
245
259
|
deployment your sink already uses to avoid running extra infrastructure.
|
|
246
260
|
- `postgres|mysql|mariadb|sqlite://…[/table]` — a shared SQL table (`dedup_key` PK,
|
|
247
261
|
`expire_at`), so multiple instances deduplicate against one another. Requires the `sqlx`
|
|
@@ -250,18 +264,22 @@ feature (pulls `sled`).
|
|
|
250
264
|
|
|
251
265
|
`sled_path` is the legacy spelling of a local sled store and is equivalent to `store: "sled://<path>"`.
|
|
252
266
|
|
|
253
|
-
```yaml
|
|
267
|
+
```yaml middleware
|
|
254
268
|
- deduplication: { store: "sled:///var/lib/mq-bridge/dedup", ttl_seconds: 3600 }
|
|
255
269
|
```
|
|
256
270
|
|
|
257
|
-
```yaml
|
|
271
|
+
```yaml middleware
|
|
258
272
|
- deduplication: { store: "mongodb://localhost:27017/etl", ttl_seconds: 3600 }
|
|
259
273
|
```
|
|
260
274
|
|
|
261
|
-
```yaml
|
|
275
|
+
```yaml middleware
|
|
262
276
|
- deduplication: { store: "postgres://user:pass@localhost/etl", ttl_seconds: 3600 }
|
|
263
277
|
```
|
|
264
278
|
|
|
279
|
+
```yaml middleware
|
|
280
|
+
- deduplication: { store: "sled:///var/lib/mq-bridge/dedup", ttl_seconds: 3600, key: "${payload:order_id}" }
|
|
281
|
+
```
|
|
282
|
+
|
|
265
283
|
When MongoDB is your sink and messages carry a business key, prefer the sink's own unique
|
|
266
284
|
index (`id_field` on the mongodb output) over this middleware — the target collection then
|
|
267
285
|
*is* the deduplication authority, with no second write. See the idempotency notes in README.
|
|
@@ -279,7 +297,7 @@ Correlates messages by a metadata key and emits them as one joined message. Inpu
|
|
|
279
297
|
| `required` | list of branch names | `[]` |
|
|
280
298
|
| `on_timeout` | `fire` \| `discard` | `fire` |
|
|
281
299
|
|
|
282
|
-
```yaml
|
|
300
|
+
```yaml middleware
|
|
283
301
|
# Count mode: wait for any 3 messages sharing a correlation_id, emit a JSON array.
|
|
284
302
|
- weak_join: { group_by: "correlation_id", expected_count: 3, timeout_ms: 5000 }
|
|
285
303
|
|
|
@@ -307,7 +325,7 @@ Accumulates single sends and forwards them as one batch. Input and output.
|
|
|
307
325
|
| `max_messages` | integer | yes |
|
|
308
326
|
| `max_delay_ms` | integer | yes |
|
|
309
327
|
|
|
310
|
-
```yaml
|
|
328
|
+
```yaml middleware
|
|
311
329
|
- buffer: { max_messages: 500, max_delay_ms: 20 }
|
|
312
330
|
```
|
|
313
331
|
|
|
@@ -322,7 +340,7 @@ Paces throughput to a target rate. Input and output.
|
|
|
322
340
|
|---|---|---|
|
|
323
341
|
| `messages_per_second` | float (> 0) | yes |
|
|
324
342
|
|
|
325
|
-
```yaml
|
|
343
|
+
```yaml middleware
|
|
326
344
|
- limiter: { messages_per_second: 250 }
|
|
327
345
|
```
|
|
328
346
|
|
|
@@ -336,7 +354,7 @@ Sleeps a fixed duration before each receive or send. Input and output.
|
|
|
336
354
|
|---|---|---|
|
|
337
355
|
| `delay_ms` | integer | yes |
|
|
338
356
|
|
|
339
|
-
```yaml
|
|
357
|
+
```yaml middleware
|
|
340
358
|
- delay: { delay_ms: 100 }
|
|
341
359
|
```
|
|
342
360
|
|
|
@@ -356,7 +374,7 @@ Persists HTTP cookies and arbitrary session values across messages. Input and ou
|
|
|
356
374
|
| `export_metadata_prefix` | string | – |
|
|
357
375
|
| `inject_metadata` | map string→string | `{}` |
|
|
358
376
|
|
|
359
|
-
```yaml
|
|
377
|
+
```yaml middleware
|
|
360
378
|
- cookie_jar:
|
|
361
379
|
shared_scope: "login-session"
|
|
362
380
|
capture_metadata_keys: ["x-csrf-token"]
|
|
@@ -380,7 +398,7 @@ output. Requires the `encryption` feature.
|
|
|
380
398
|
| `key` | string — base64-encoded 32-byte key; `${env:VAR}` reads it from the environment | required |
|
|
381
399
|
| `decrypt_keys` | map key_id → key | `{}` |
|
|
382
400
|
|
|
383
|
-
```yaml
|
|
401
|
+
```yaml middleware
|
|
384
402
|
- encryption: { key: "${env:MQB_ENC_KEY}" }
|
|
385
403
|
```
|
|
386
404
|
|
|
@@ -402,7 +420,7 @@ Do **not** combine this middleware with a sink's batch `compression` on the same
|
|
|
402
420
|
ciphertext does not compress. For compressed *and* encrypted data at rest, use the `file` /
|
|
403
421
|
`object_store` endpoints' own fields instead, which apply compress-then-encrypt per batch:
|
|
404
422
|
|
|
405
|
-
```yaml
|
|
423
|
+
```yaml endpoint
|
|
406
424
|
output:
|
|
407
425
|
file:
|
|
408
426
|
path: "data.enc"
|
|
@@ -443,7 +461,7 @@ feature.
|
|
|
443
461
|
| `algorithm` | `none` \| `gzip` \| `lz4` \| `zstd` | `zstd` |
|
|
444
462
|
| `max_decompressed_bytes` | integer — reject a payload that decompresses larger than this (bomb guard); consumer side only | unset (no limit) |
|
|
445
463
|
|
|
446
|
-
```yaml
|
|
464
|
+
```yaml middleware
|
|
447
465
|
- compression: { algorithm: zstd }
|
|
448
466
|
```
|
|
449
467
|
|
|
@@ -464,7 +482,7 @@ endpoints' own `compression`/`encryption` fields instead.
|
|
|
464
482
|
Emits throughput, latency and error metrics for the endpoint. Input and output. Requires the
|
|
465
483
|
`metrics` feature. Takes no options; its presence enables collection.
|
|
466
484
|
|
|
467
|
-
```yaml
|
|
485
|
+
```yaml middleware
|
|
468
486
|
- metrics: {}
|
|
469
487
|
```
|
|
470
488
|
|
|
@@ -480,7 +498,7 @@ Deliberate fault injection for testing recovery paths. Input and output.
|
|
|
480
498
|
| `trigger_on_message` | integer (1-indexed) | – (every message) |
|
|
481
499
|
| `enabled` | bool | `true` |
|
|
482
500
|
|
|
483
|
-
```yaml
|
|
501
|
+
```yaml middleware
|
|
484
502
|
- random_panic: { mode: disconnect, trigger_on_message: 500 }
|
|
485
503
|
```
|
|
486
504
|
|
|
@@ -488,6 +506,24 @@ Deliberate fault injection for testing recovery paths. Input and output.
|
|
|
488
506
|
non-retryable one — useful for exercising a `dlq`. Keep `enabled: false` in committed configs
|
|
489
507
|
rather than deleting the block.
|
|
490
508
|
|
|
509
|
+
The middleware block alone is **not** enough: fault injection is gated per route by
|
|
510
|
+
`allow_fault_injection`, which defaults to `false`. Copying only the snippet above leaves the
|
|
511
|
+
middleware inert (the route logs that it is disabled). A complete, working configuration:
|
|
512
|
+
|
|
513
|
+
```yaml route
|
|
514
|
+
flaky_test_route:
|
|
515
|
+
allow_fault_injection: true
|
|
516
|
+
input:
|
|
517
|
+
memory: { topic: "in" }
|
|
518
|
+
middlewares:
|
|
519
|
+
- random_panic: { mode: disconnect, trigger_on_message: 500 }
|
|
520
|
+
output:
|
|
521
|
+
memory: { topic: "out" }
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
`allow_fault_injection: true` is intended for test configurations only. Do not enable it — or
|
|
525
|
+
the `random_panic` middleware — in production configs.
|
|
526
|
+
|
|
491
527
|
### `custom` (middleware)
|
|
492
528
|
|
|
493
529
|
Delegates to a factory you registered programmatically.
|
|
@@ -497,7 +533,7 @@ Delegates to a factory you registered programmatically.
|
|
|
497
533
|
| `name` | string | yes |
|
|
498
534
|
| `config` | any JSON | yes |
|
|
499
535
|
|
|
500
|
-
```yaml
|
|
536
|
+
```yaml middleware
|
|
501
537
|
- custom:
|
|
502
538
|
name: "my_enricher"
|
|
503
539
|
config: { lookup_url: "http://enrich.internal" }
|
|
@@ -545,7 +581,7 @@ use mq_bridge::route::register_endpoint;
|
|
|
545
581
|
register_endpoint("common_queue", Endpoint::new_memory("shared_memory_topic", 100));
|
|
546
582
|
```
|
|
547
583
|
|
|
548
|
-
```yaml
|
|
584
|
+
```yaml route
|
|
549
585
|
enrich:
|
|
550
586
|
input: { ref: "common_queue" }
|
|
551
587
|
output: { nats: { subject: "enriched", url: "nats://localhost:4222" } }
|
|
@@ -564,7 +600,7 @@ nesting depth is bounded.
|
|
|
564
600
|
|
|
565
601
|
Publishes each message to every listed endpoint. Output only.
|
|
566
602
|
|
|
567
|
-
```yaml
|
|
603
|
+
```yaml endpoint
|
|
568
604
|
output:
|
|
569
605
|
fanout:
|
|
570
606
|
- kafka: { topic: "audit", url: "localhost:9092" }
|
|
@@ -585,7 +621,7 @@ Content-based routing: picks a destination by the value of a **metadata key**.
|
|
|
585
621
|
| `cases` | map value → Endpoint | yes |
|
|
586
622
|
| `default` | Endpoint | no |
|
|
587
623
|
|
|
588
|
-
```yaml
|
|
624
|
+
```yaml endpoint
|
|
589
625
|
output:
|
|
590
626
|
switch:
|
|
591
627
|
metadata_key: "http_status_code"
|
|
@@ -611,7 +647,7 @@ turning a request/reply exchange into a one-way flow.
|
|
|
611
647
|
| `to` | Endpoint (request-capable) | yes |
|
|
612
648
|
| `forward_to` | Endpoint | yes |
|
|
613
649
|
|
|
614
|
-
```yaml
|
|
650
|
+
```yaml endpoint
|
|
615
651
|
output:
|
|
616
652
|
request:
|
|
617
653
|
to: { http: { url: "https://api.internal/score" } }
|
|
@@ -628,7 +664,7 @@ status key such as `http_status_code`.
|
|
|
628
664
|
Replies to the origin of the current request. Output only, and the recommended way to build
|
|
629
665
|
request/reply routes.
|
|
630
666
|
|
|
631
|
-
```yaml
|
|
667
|
+
```yaml route
|
|
632
668
|
http_echo:
|
|
633
669
|
input: { http: { url: "0.0.0.0:8080" } }
|
|
634
670
|
output: { response: {} }
|
|
@@ -644,7 +680,7 @@ pipeline. See [README.md](README.md#patterns-request-response).
|
|
|
644
680
|
An output endpoint that **ignores the incoming payload** and instead reads one message from
|
|
645
681
|
the wrapped consumer, returning it as the response. The inbound message is purely a trigger.
|
|
646
682
|
|
|
647
|
-
```yaml
|
|
683
|
+
```yaml route
|
|
648
684
|
# HTTP GET pulls the next message off a Kafka topic.
|
|
649
685
|
poll_api:
|
|
650
686
|
input: { http: { url: "0.0.0.0:8080", method: "GET" } }
|
|
@@ -670,7 +706,7 @@ source).
|
|
|
670
706
|
|
|
671
707
|
Accepts either a bare string or the full map form:
|
|
672
708
|
|
|
673
|
-
```yaml
|
|
709
|
+
```yaml endpoint
|
|
674
710
|
output: { static: "OK" } # shorthand, body JSON-encoded
|
|
675
711
|
|
|
676
712
|
output:
|
|
@@ -707,7 +743,7 @@ structure — append `| raw` to a token to splice it verbatim. To emit a literal
|
|
|
707
743
|
`${…}`, write `$${…}` (a bare `$$` is left as-is); any `${…}` with an unknown namespace is also
|
|
708
744
|
left untouched.
|
|
709
745
|
|
|
710
|
-
```yaml
|
|
746
|
+
```yaml endpoint
|
|
711
747
|
output:
|
|
712
748
|
static:
|
|
713
749
|
body: '{"error":"not found","id":"${message:id}","at":"${gen:now}"}'
|
|
@@ -726,7 +762,7 @@ bodies between routes.
|
|
|
726
762
|
| `correlation_id` | string | **required on consumers, must be unset on publishers** |
|
|
727
763
|
| `capacity` | integer | default `100`, per partition |
|
|
728
764
|
|
|
729
|
-
```yaml
|
|
765
|
+
```yaml endpoint
|
|
730
766
|
output:
|
|
731
767
|
stream_buffer: { topic: "responses" } # publisher: no correlation_id
|
|
732
768
|
|
|
@@ -741,7 +777,7 @@ and ignores it. Primarily wired up via `HttpConfig::stream_response_to`.
|
|
|
741
777
|
|
|
742
778
|
Discards every message. Output only. This is the **default output** when a route omits one.
|
|
743
779
|
|
|
744
|
-
```yaml
|
|
780
|
+
```yaml route
|
|
745
781
|
drain:
|
|
746
782
|
input: { kafka: { topic: "noisy", url: "localhost:9092" } }
|
|
747
783
|
output: null # a bare YAML null
|
|
@@ -762,7 +798,7 @@ Delegates to a factory you registered programmatically.
|
|
|
762
798
|
| `name` | string | yes |
|
|
763
799
|
| `config` | any JSON | yes |
|
|
764
800
|
|
|
765
|
-
```yaml
|
|
801
|
+
```yaml endpoint
|
|
766
802
|
output:
|
|
767
803
|
custom:
|
|
768
804
|
name: "my_sink"
|
|
@@ -72,7 +72,7 @@ theirs. The run brief lives in [`mq-bridge-app-benchmark-prompt.md`](mq-bridge-a
|
|
|
72
72
|
|
|
73
73
|
| Scenario | Payload | Batch | Concurrency | Source → Sink | Result |
|
|
74
74
|
| --- | --- | --- | --- | --- | --- |
|
|
75
|
-
| Bulk-copy throughput | 7-col mixed-type rows, 1,000,000 rows | 1024 | 4 | postgres (keyset cursor) → file (JSONL) | **
|
|
75
|
+
| Bulk-copy throughput | 7-col mixed-type rows, 1,000,000 rows | 1024 | 4 | postgres (keyset cursor) → file (JSONL) | **384,615 rows/s** (2.600 s) |
|
|
76
76
|
|
|
77
77
|
Command: `mq-bridge-app copy --from postgres://…?table=…&cursor_column=id --to file://…?format=raw --drain --batch-size 1024 --concurrency 4`, wall-clocked. Requires an index on the cursor column (`CREATE INDEX ON <table>(id)`) — without it the keyset-pagination reader (`WHERE id > $cursor ORDER BY id LIMIT batch`) does a full scan per batch (near-quadratic).
|
|
78
78
|
|
|
@@ -82,10 +82,10 @@ Same source table (`bench`: 1,000,000 rows, 7 mixed-type columns), same Postgres
|
|
|
82
82
|
|
|
83
83
|
| Scenario | Payload | Batch | Concurrency | Source → Sink | Throughput | Peak RSS |
|
|
84
84
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
85
|
-
| mq-bridge-app `copy` | 7-col, 1,000,000 rows | 1024 | 1 | postgres (keyset cursor) → file (JSONL) | **
|
|
85
|
+
| mq-bridge-app `copy` | 7-col, 1,000,000 rows | 1024 | 1 | postgres (keyset cursor) → file (JSONL) | **338,066 rows/s** | 39.8 MiB |
|
|
86
86
|
| Meltano (`tap-postgres` → `target-jsonl`) | 7-col, 1,000,000 rows | default Singer config | — | postgres → JSONL | 15,356 rows/s | 599.7 MiB |
|
|
87
87
|
|
|
88
|
-
**~
|
|
88
|
+
**~22x faster and ~15x leaner in peak memory** than Meltano in this scenario. Full setup (including the Meltano project config) is in [mq-bridge-app's `benches/etl/README.md`](https://github.com/marcomq/mq-bridge-app/blob/dev/benches/etl/README.md#5--postgres--jsonl-vs-meltano-tap-postgres--target-jsonl).
|
|
89
89
|
|
|
90
90
|
### Preliminary run — CSV → JSONL vs. Meltano
|
|
91
91
|
|
|
@@ -93,10 +93,10 @@ Same seeded dataset both sides, same machine, one-shot full-file CSV → local J
|
|
|
93
93
|
|
|
94
94
|
| Scenario | Payload | Batch | Concurrency | Source → Sink | Throughput | Peak RSS |
|
|
95
95
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
96
|
-
| mq-bridge-app `copy` | 7-col mixed-type, 1,000,000 rows (~116 MiB) | 1024 | 1 | file (CSV) → file (JSONL) | **
|
|
96
|
+
| mq-bridge-app `copy` | 7-col mixed-type, 1,000,000 rows (~116 MiB) | 1024 | 1 | file (CSV) → file (JSONL) | **1,133,786 rows/s** | 21.9 MiB |
|
|
97
97
|
| Meltano (`tap-csv` → `target-jsonl`) | 7-col mixed-type, 1,000,000 rows | default Singer config | — | file (CSV) → JSONL | ~19,500 rows/s | 443.8 MiB |
|
|
98
98
|
|
|
99
|
-
**~
|
|
99
|
+
**~58x faster and ~20x leaner in peak memory** than Meltano in this scenario. Full setup is in [mq-bridge-app's `benches/etl/README.md`](https://github.com/marcomq/mq-bridge-app/blob/dev/benches/etl/README.md#6--csv--jsonl-vs-meltano).
|
|
100
100
|
|
|
101
101
|
## Status
|
|
102
102
|
|
|
@@ -478,6 +478,14 @@
|
|
|
478
478
|
"description": "Deduplication middleware configuration.\n\nPrevents duplicate messages from being processed using a sled, MongoDB, or SQL backend.\nMessages are identified by their deduplication key and removed after the TTL expires.",
|
|
479
479
|
"type": "object",
|
|
480
480
|
"properties": {
|
|
481
|
+
"key": {
|
|
482
|
+
"description": "Dedup key template, e.g. `${payload:order_id}`. Defaults to `message_id`.",
|
|
483
|
+
"type": [
|
|
484
|
+
"string",
|
|
485
|
+
"null"
|
|
486
|
+
],
|
|
487
|
+
"default": null
|
|
488
|
+
},
|
|
481
489
|
"sled_path": {
|
|
482
490
|
"description": "Local Sled directory (legacy). Prefer `store`.",
|
|
483
491
|
"type": [
|
|
@@ -922,9 +930,16 @@
|
|
|
922
930
|
]
|
|
923
931
|
},
|
|
924
932
|
{
|
|
925
|
-
"type": "
|
|
933
|
+
"type": "object",
|
|
926
934
|
"format": "structural_endpoint",
|
|
927
|
-
"
|
|
935
|
+
"properties": {
|
|
936
|
+
"null": {
|
|
937
|
+
"type": "null"
|
|
938
|
+
}
|
|
939
|
+
},
|
|
940
|
+
"required": [
|
|
941
|
+
"null"
|
|
942
|
+
]
|
|
928
943
|
}
|
|
929
944
|
],
|
|
930
945
|
"unevaluatedProperties": false
|
|
@@ -963,7 +978,7 @@
|
|
|
963
978
|
"type": "object",
|
|
964
979
|
"properties": {
|
|
965
980
|
"compression": {
|
|
966
|
-
"description": "Per-batch compression (`none`, `gzip`, `lz4`, `zstd`). Requires the `compression` feature
|
|
981
|
+
"description": "Per-batch compression (`none`, `gzip`, `lz4`, `zstd`). Requires the `compression` feature. Publishers: always. Consumers: must match, and only the default `consume` mode reads it.",
|
|
967
982
|
"$ref": "#/$defs/Compression",
|
|
968
983
|
"default": "none"
|
|
969
984
|
},
|
|
@@ -975,7 +990,7 @@
|
|
|
975
990
|
]
|
|
976
991
|
},
|
|
977
992
|
"encryption": {
|
|
978
|
-
"description": "At-rest AEAD encryption applied after compression. Requires the `encryption` feature
|
|
993
|
+
"description": "At-rest AEAD encryption applied after compression. Requires the `encryption` feature. Publishers: always. Consumers: must match, and only the default `consume` mode reads it.",
|
|
979
994
|
"anyOf": [
|
|
980
995
|
{
|
|
981
996
|
"$ref": "#/$defs/EncryptionConfig"
|
|
@@ -2609,7 +2624,7 @@
|
|
|
2609
2624
|
"minimum": 0
|
|
2610
2625
|
},
|
|
2611
2626
|
"temporary_slot": {
|
|
2612
|
-
"description": "
|
|
2627
|
+
"description": "Ephemeral run: drop the slot when the route stops. Not restart-safe; a hard crash leaks it.",
|
|
2613
2628
|
"type": "boolean",
|
|
2614
2629
|
"default": false
|
|
2615
2630
|
},
|
|
@@ -86,6 +86,7 @@ class DeadLetterQueueMiddleware(TypedDict, total=False):
|
|
|
86
86
|
|
|
87
87
|
class DeduplicationMiddleware(TypedDict, total=False):
|
|
88
88
|
"""Deduplication middleware configuration."""
|
|
89
|
+
key: Optional[str]
|
|
89
90
|
sled_path: Optional[str]
|
|
90
91
|
store: Optional[str]
|
|
91
92
|
ttl_seconds: Required[int]
|
|
@@ -113,7 +114,36 @@ class EncryptionConfig(TypedDict, total=False):
|
|
|
113
114
|
|
|
114
115
|
class Endpoint(TypedDict, total=False):
|
|
115
116
|
"""Represents a connection point for messages, which can be a source (input) or a sink (output)."""
|
|
117
|
+
amqp: AmqpConfig
|
|
118
|
+
aws: AwsConfig
|
|
119
|
+
clickhouse: ClickHouseConfig
|
|
120
|
+
custom: Dict[str, Any]
|
|
121
|
+
fanout: List[Endpoint]
|
|
122
|
+
file: FileConfig
|
|
123
|
+
grpc: GrpcConfig
|
|
124
|
+
http: HttpConfig
|
|
125
|
+
ibmmq: IbmMqConfig
|
|
126
|
+
kafka: KafkaConfig
|
|
127
|
+
memory: MemoryConfig
|
|
116
128
|
middlewares: List[Middleware]
|
|
129
|
+
mongodb: MongoDbConfig
|
|
130
|
+
mqtt: MqttConfig
|
|
131
|
+
nats: NatsConfig
|
|
132
|
+
null: Any
|
|
133
|
+
object_store: ObjectStoreConfig
|
|
134
|
+
postgres_cdc: PostgresCdcConfig
|
|
135
|
+
reader: Endpoint
|
|
136
|
+
redis_streams: RedisStreamsConfig
|
|
137
|
+
ref: str
|
|
138
|
+
request: RequestForwardConfig
|
|
139
|
+
response: ResponseConfig
|
|
140
|
+
sled: SledConfig
|
|
141
|
+
sqlx: SqlxConfig
|
|
142
|
+
static: StaticConfig
|
|
143
|
+
stream_buffer: StreamBufferConfig
|
|
144
|
+
switch: SwitchConfig
|
|
145
|
+
websocket: WebSocketConfig
|
|
146
|
+
zeromq: ZeroMqConfig
|
|
117
147
|
|
|
118
148
|
|
|
119
149
|
class FileConfig(TypedDict, total=False):
|