Skip to content

fix(sdk): reject zero durations that spin client loops - #3891

Open
ethanlin01x wants to merge 5 commits into
apache:masterfrom
ethanlin01x:fix/sdk-zero-duration-fence
Open

fix(sdk): reject zero durations that spin client loops#3891
ethanlin01x wants to merge 5 commits into
apache:masterfrom
ethanlin01x:fix/sdk-zero-duration-fence

Conversation

@ethanlin01x

Copy link
Copy Markdown
Contributor

Which issue does this PR address?

Relates to #3776 (Found while reviewing)

Rationale

Zero-valued durations reach loops that spin or panic. The CLI hits this today: IggyDuration::from_str maps 0, none, disabled and unlimited to the same zero, so --tcp-heartbeat-interval none produces a ping loop with no delay between round trips.

#3776 guarded this inside the Python binding, but the hazard is not Python-specific. The fence belongs in the Rust SDK, where every binding funnels through.

What changed?

Validation added to five functions that already return Result:

  • TcpClient::create, QuicClient::create, WebSocketClient::create — zero heartbeat_interval, or zero reconnection.interval with unlimited retries. The heartbeat task is transport-agnostic, so all three shared the bug.
  • IggyConsumer::init — zero init_retry_interval (panics time::interval), polling_retry_interval (spins a core), or auto-commit interval (background task spins from spawn).
  • ProducerCore::init — zero send retries interval, and only when a retry count is set.

Zero stays legal where it means something: bounded fast-retry, reconnection disabled, auto-commit modes carrying no interval, and no retry budget.

Behavior change:

--tcp-heartbeat-interval none and its --quic- / --websocket- equivalents now fail with InvalidConfiguration instead of silently spinning.

Local Execution

  • Passed
  • Pre-commit hooks ran

AI Usage

  1. Which tools? Claude
  2. Scope of usage? help implement and review this PR
  3. How did you verify the generated code works correctly? Unit tests pin each rejected and each still-legal combination
  4. Can you explain every line of the code if asked? Yes, all the changes are checked by the human.

A zero heartbeat interval pings without pause, and a zero reconnection
interval with unlimited retries spins on connect. Found during review of apache#3776.
A zero init retry interval panics the timer it builds; a zero polling retry
interval and a zero auto-commit interval both spin.
Only when a retry count is set, since send_internal never reads the interval
without one.
The heartbeat loop is transport-agnostic, so the TCP fence left both open.
@ethanlin01x ethanlin01x changed the title fix(sdk): reject zero durations that spin client loops fix(sdk): reject zero durations that spin client loops Aug 16, 2026
@codecov

codecov Bot commented Aug 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.83333% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.46%. Comparing base (7c0fd68) to head (f923068).

Files with missing lines Patch % Lines
core/sdk/src/clients/consumer.rs 96.62% 0 Missing and 3 partials ⚠️
core/sdk/src/quic/quic_client.rs 95.08% 0 Missing and 3 partials ⚠️
core/sdk/src/tcp/tcp_client.rs 95.08% 0 Missing and 3 partials ⚠️
core/sdk/src/websocket/websocket_client.rs 95.08% 0 Missing and 3 partials ⚠️
core/sdk/src/clients/producer.rs 97.50% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #3891      +/-   ##
============================================
- Coverage     82.96%   81.46%   -1.51%     
  Complexity     1339     1339              
============================================
  Files          1218     1218              
  Lines        165595   159850    -5745     
  Branches     133910   128290    -5620     
============================================
- Hits         137394   130229    -7165     
- Misses        24540    25593    +1053     
- Partials       3661     4028     +367     
Components Coverage Δ
Rust Core 81.71% <95.83%> (-1.78%) ⬇️
Java SDK 66.55% <ø> (ø)
C# SDK 74.77% <ø> (-1.66%) ⬇️
Python SDK 90.00% <ø> (ø)
PHP SDK 84.48% <ø> (ø)
Node SDK 95.78% <ø> (+0.10%) ⬆️
Go SDK 69.04% <ø> (ø)
Files with missing lines Coverage Δ
...es/configuration/quic_config/quic_client_config.rs 100.00% <ø> (ø)
...ion/quic_config/quic_client_reconnection_config.rs 38.09% <ø> (ø)
...ypes/configuration/tcp_config/tcp_client_config.rs 100.00% <ø> (ø)
...ation/tcp_config/tcp_client_reconnection_config.rs 100.00% <ø> (ø)
...ration/websocket_config/websocket_client_config.rs 61.44% <ø> (ø)
...ket_config/websocket_client_reconnection_config.rs 66.66% <ø> (ø)
core/sdk/src/clients/producer.rs 68.21% <97.50%> (+1.86%) ⬆️
core/sdk/src/clients/consumer.rs 74.42% <96.62%> (+2.65%) ⬆️
core/sdk/src/quic/quic_client.rs 76.77% <95.08%> (+1.69%) ⬆️
core/sdk/src/tcp/tcp_client.rs 77.43% <95.08%> (+1.74%) ⬆️
... and 1 more

... and 175 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ethanlin01x
ethanlin01x marked this pull request as ready for review August 16, 2026 03:00
@ethanlin01x

Copy link
Copy Markdown
Contributor Author

/request-review @hubcio

@github-actions github-actions Bot added the S-waiting-on-review PR is waiting on a reviewer label Aug 16, 2026
@ethanlin01x

Copy link
Copy Markdown
Contributor Author

/ready

@github-actions
github-actions Bot requested a review from hubcio August 16, 2026 03:01
@haubur

haubur commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

The problem is real for consumers:

producers:

and connection lifecycle:

Clarification:

  • The problem occurs if manually setting a IggyDuration equal to zero.
  • No default path actually sets an IggyDuration with zero.
  • panics occur for IggyDuration in retry_intervals not for heartbeat_intervals

Solution:

  • Having IggyDuration falling to 0 for "unlimited", "disabled" and "none" is a little misleading.
  • Since it's a common type there might be unobserved behavior in other places should we change it now.
  • To avoid panics, I would prefer not checking in methods calls as done in the PR but enforcing the proposed guards on a type level e.g. by introducing a NonZeroIggyDuration.

@ethanlin01x

Copy link
Copy Markdown
Contributor Author

@haubur

Thanks for the review.

I agree that using NonZeroIggyDuration is cleaner than checking in each method. My concern is that some of these are cross-field rules, so I am not sure a type can enforce them. For example, interval = 0 is still valid when max_retries is bounded. Changing the field type would also be a breaking change for the SDK API.

So I would prefer to keep the current approach. What do you think?

@haubur

haubur commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

@ethanlin01x fair points.

  • A NonZeroIggyDuration assumes that 0 intervals are actually undesirable, which I would argue makes sense. I think its reasonable to enforce waiting a bit before retrying (instead of rapid fire). You can still set the duration to some very low time period if you want that, but that's intended behavior than not implicit as it is now.
  • It would be a breaking API change, true. If thats something we want at this point is a question to the maintainers I guess, because there is a release coming up this week AFAIK.

@spetz

spetz commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

@haubur breaking changes are totally fine at this stage, as we're very close to the next release, with lots of breaking changes anyway :)
And yes, I do agree, there should be at least like a 1 ms wait before the retries (while on the other hand, no wait at all for data producer/consumer running as a busy loop is totally fine for specific use cases).

@haubur

haubur commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Thanks @spetz! So @ethanlin01x lets have a NonZeroIggyDuration for retries and heartbeats, while keeping the busy loop for AutoCommit on an interval = 0. Would you want to rewrite? Otherwise, I can also take this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review PR is waiting on a reviewer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants