feat: Add pressure-aware receiver rate throttling#3529
Conversation
There was a problem hiding this comment.
Pull request overview
This PR implements RFC 0002 pressure-aware receiver rate throttling for otap-dataflow, introducing a receiver-local (lock-free) rate limiter driven by the existing process memory pressure signal. It also adds capability-based validation so unsupported receiver/unit combinations fail closed during startup and engine receiver construction.
Changes:
- Add a receiver-local token-bucket/GCRA-style rate limiter and a gRPC fast-fail Tower layer, plus OTLP/Syslog receiver integrations (including retryable OTLP responses and Syslog drop behavior).
- Extend config/policy resolution and validation to support a
rate_limitpolicy, including byte-unit parsing forrequest_bytes/secondand semantic validation requiring a configured memory limiter. - Add receiver capability metadata (
ReceiverFactory::supported_rate_units) and enforce it in controller startup validation and engine receiver construction.
Reviewed changes
Copilot reviewed 40 out of 40 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| rust/otap-dataflow/src/main.rs | Updates controller startup validation call sites for the new rate-limit policy parameter. |
| rust/otap-dataflow/docs/memory-limiter-phase1.md | Documents soft-pressure interaction with receiver admission policies and adds new rate-limit metrics/events. |
| rust/otap-dataflow/docs/admin/live-reconfiguration.md | Documents that runtime memory limiter mutation is rejected. |
| rust/otap-dataflow/crates/otap/tests/pipeline_tests.rs | Updates pipeline construction tests for new pipeline build parameter. |
| rust/otap-dataflow/crates/otap/tests/internal_telemetry_metrics.rs | Updates internal telemetry tests for new pipeline build parameter. |
| rust/otap-dataflow/crates/otap/tests/durable_buffer_processor_tests.rs | Updates durable buffer tests for new pipeline build parameter. |
| rust/otap-dataflow/crates/otap/tests/core_node_liveness_tests.rs | Updates liveness tests for new pipeline build parameter. |
| rust/otap-dataflow/crates/otap/src/rate_limiter.rs | Adds the receiver-local pressure-aware rate limiter implementation + unit tests. |
| rust/otap-dataflow/crates/otap/src/rate_limit_layer.rs | Adds a Tower layer for gRPC fast-fail when the rate bucket is exhausted. |
| rust/otap-dataflow/crates/otap/src/otlp_metrics.rs | Adds OTLP receiver counters for refused/would-refuse rate limiting. |
| rust/otap-dataflow/crates/otap/src/otlp_http.rs | Adds OTLP HTTP rate-limit refusal paths (503 + Retry-After) and accounting/metrics updates. |
| rust/otap-dataflow/crates/otap/src/otap_grpc/otlp/server_new.rs | Adds OTLP gRPC rate-limit refusal handling (RESOURCE_EXHAUSTED + retry pushback) and metrics updates. |
| rust/otap-dataflow/crates/otap/src/lib.rs | Exposes the new rate limiter and rate-limit middleware modules. |
| rust/otap-dataflow/crates/engine/tests/extension_e2e.rs | Updates engine extension E2E tests for new receiver factory capability field + pipeline build arg. |
| rust/otap-dataflow/crates/engine/src/lib.rs | Adds supported_rate_units to ReceiverFactory and enforces receiver/unit compatibility during receiver construction. |
| rust/otap-dataflow/crates/engine/src/config.rs | Extends ReceiverConfig to carry an optional resolved rate_limit policy into receivers. |
| rust/otap-dataflow/crates/core-nodes/src/receivers/traffic_generator/mod.rs | Declares no supported rate units for traffic generator receiver. |
| rust/otap-dataflow/crates/core-nodes/src/receivers/topic_receiver/mod.rs | Declares no supported rate units for topic receiver. |
| rust/otap-dataflow/crates/core-nodes/src/receivers/syslog_cef_receiver/README.md | Documents Syslog/CEF rate-limit semantics and adds new metrics/events. |
| rust/otap-dataflow/crates/core-nodes/src/receivers/syslog_cef_receiver/mod.rs | Integrates local rate limiting into Syslog/CEF UDP + TCP/TLS ingestion and adds metrics/tests. |
| rust/otap-dataflow/crates/core-nodes/src/receivers/otlp_receiver/README.md | Documents new OTLP rate-limit metrics. |
| rust/otap-dataflow/crates/core-nodes/src/receivers/otlp_receiver/mod.rs | Integrates rate limiting into OTLP receiver (gRPC + HTTP paths) and declares supported unit. |
| rust/otap-dataflow/crates/core-nodes/src/receivers/otap_receiver/mod.rs | Declares no supported rate units for OTAP receiver. |
| rust/otap-dataflow/crates/core-nodes/src/receivers/journald_receiver/mod.rs | Declares no supported rate units for journald receiver. |
| rust/otap-dataflow/crates/core-nodes/src/receivers/internal_telemetry_receiver/mod.rs | Declares no supported rate units for internal telemetry receiver. |
| rust/otap-dataflow/crates/core-nodes/src/receivers/host_metrics_receiver/mod.rs | Declares no supported rate units for host metrics receiver. |
| rust/otap-dataflow/crates/core-nodes/src/exporters/otlp_http_exporter/mod.rs | Updates OTLP HTTP exporter tests for the new server serve signature (rate limiter parameter). |
| rust/otap-dataflow/crates/controller/src/startup.rs | Validates receiver rate-limit capability at startup using supported_rate_units; updates engine validation to use resolved pipelines. |
| rust/otap-dataflow/crates/controller/src/live_control/runtime.rs | Threads resolved rate_limit policy into runtime pipeline construction. |
| rust/otap-dataflow/crates/controller/src/live_control/planning.rs | Rejects live reconciliation requests that would mutate the process-wide memory limiter config. |
| rust/otap-dataflow/crates/controller/src/live_control_tests.rs | Adds live-control test coverage for rejecting runtime memory limiter mutation; updates test receiver factories. |
| rust/otap-dataflow/crates/controller/src/lib.rs | Threads resolved rate_limit policy through controller pipeline build paths and adds semantic validation on controller start. |
| rust/otap-dataflow/crates/contrib-nodes/src/receivers/user_events_receiver/mod.rs | Declares no supported rate units for user events receiver. |
| rust/otap-dataflow/crates/contrib-nodes/src/receivers/etw_receiver/mod.rs | Declares no supported rate units for ETW receiver. |
| rust/otap-dataflow/crates/config/src/policy.rs | Adds rate_limit to policies + resolution + compatibility; defines RateLimitPolicy (including byte-unit parsing) and validation/tests. |
| rust/otap-dataflow/crates/config/src/engine/validate.rs | Adds semantic validation requiring a configured memory limiter when any rate_limit policy is present. |
| rust/otap-dataflow/crates/config/src/engine/resolve.rs | Ensures internal observability pipelines do not inherit user-facing rate_limit policy. |
| rust/otap-dataflow/crates/config/src/engine.rs | Adds policy resolution tests covering rate-limit override precedence and observability scoping. |
| rust/otap-dataflow/.chloggen/syslog-cef-rate-limit.yaml | Changelog entry for Syslog/CEF pressure-aware message-rate limiting. |
| rust/otap-dataflow/.chloggen/pressure-aware-rate-throttling.yaml | Changelog entry for OTLP pressure-aware rate throttling and the breaking ReceiverFactory embedding API change. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Pull request dashboard statusStatus last refreshed: 2026-07-25 21:05:08 UTC.
This automated status or its linked feedback items may be incorrect. If something looks wrong, please report it with the result you expected. If you believe this pull request is incorrectly routed as waiting on the author, comment |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #3529 +/- ##
==========================================
+ Coverage 86.88% 86.91% +0.03%
==========================================
Files 782 784 +2
Lines 319391 321151 +1760
==========================================
+ Hits 277498 279136 +1638
- Misses 41369 41491 +122
Partials 524 524
🚀 New features to boost your workflow:
|
# Conflicts: # rust/otap-dataflow/crates/config/src/engine/resolve.rs # rust/otap-dataflow/crates/controller/src/lib.rs # rust/otap-dataflow/crates/controller/src/startup.rs # rust/otap-dataflow/crates/core-nodes/src/receivers/otlp_receiver/README.md # rust/otap-dataflow/crates/core-nodes/src/receivers/otlp_receiver/mod.rs # rust/otap-dataflow/crates/otap/src/otap_grpc/otlp/server_new.rs # rust/otap-dataflow/crates/otap/src/otlp_http.rs # rust/otap-dataflow/crates/otap/src/otlp_metrics.rs # rust/otap-dataflow/docs/memory-limiter-phase1.md
| allow: 2000 | ||
| interval: 1s | ||
| burst: 2000 | ||
| pressure: soft |
There was a problem hiding this comment.
Feedback on configuration to align with #3583.
- I was wondering if rate limits belong under
resources. We haveresources::memory_limiteralready, so I think this should berate_limiter; then, also I expect potentially multiple rate limits, so I think this should berate_limiters. - Inside the rate limiter policy, I the
allow,interval, andburstparameters are specific to a token bucket limiter, and I expect other kinds of limiter configuration in the policies framework, so I would indent these three undertoken_bucket.
groups:
default:
pipelines:
main:
policies:
resources:
rate_limiters:
first_rate_limiter:
unit: request_bytes/second
token_bucket:
allow: 2000
interval: 1s
burst: 2000
Change Summary
Implements RFC 0002 pressure-aware receiver rate throttling.
This adds a receiver-local, lock-free rate limiter driven by the existing memory pressure signal. V1 supports:
request_bytes/second, measured as decompressed OTLP payload bytesmessages/second, measured per UDP datagram or emitted TCP/TLS record fragmentreceiver_instanceaggregationsoftpressure and aboveenforceandobserve_onlymodesOTLP returns protocol-native retryable responses when throttled: HTTP
503withRetry-After, and gRPCRESOURCE_EXHAUSTEDwithgrpc-retry-pushback-ms. Syslog / CEF drops over-limit messages/fragments while keeping TCP/TLS connections open; hard memory pressure behavior is unchanged.The PR also adds receiver capability validation through
ReceiverFactory::supported_rate_units, so unsupported receiver/unit combinations fail closed at startup and at engine receiver construction time.V1 limitations called out in docs:
rate_limitto receivers that support the configured unitWhat issue does this PR close?
How are these changes tested?
Unit and integration coverage added for:
RESOURCE_EXHAUSTEDand retry pushback metadataLocal validation run:
cargo fmt --allcargo check -p otap-df-otapcargo check -p otap-df-core-nodescargo check -p otap-df-controllercargo testruns for rate limiter, OTLP, syslog, and live-control casesnpx markdownlint-cli2on changed Markdown filespython3 tools/sanitycheck.pyBenchmark details:
Hardware:
Happy-path local throughput comparison:
main, rate limiting absent:198,878 logs/sec, stdev170198,922 logs/sec, stdev93198,868 logs/sec, stdev11Result: no measurable happy-path throughput regression in this local benchmark.
Are there any user-facing changes?
Yes.
This adds new pressure-aware rate throttling policy support for OTLP and Syslog / CEF receivers, new receiver refusal metrics, and new documented syslog rate-drop behavior.
This is also a source-breaking embedding API change: custom receiver embedders must declare supported rate-limit units on
ReceiverFactory.Changelog
.chloggen/*.yamlentrychore(indicated in title)