Skip to content

Unexpected Behavior: ThroughputControl sleep interval is always 50ms, ignoring periodInMillis configuration. #653

@chhil

Description

@chhil

this.sleep[i] = Math.min(Math.max (periodInMillis[i]/10, 500L),50L);

  • Inner Part: Math.max(periodInMillis[i]/10, 500L)
    This part says: "Calculate 10% of the period, but if that's less than 500, use 500 instead."
    The result of this inner calculation will always be a number greater than or equal to 500.

    • If periodInMillis is 1000, 1000/10 = 100. Math.max(100, 500) is 500.
    • If periodInMillis is 6000, 6000/10 = 600. Math.max(600, 500) is 600.
  • Outer Part: Math.min(innerResult, 50L)
    This part says: "Take the result from the inner part (which is always >= 500) and compare it to 50. Return the smaller of the two."
    Since 50 is always smaller than any number greater than or equal to 500, the result of this outer calculation will always be 50.

This has unintentionally hard-codes the sleep duration to a fixed 50ms. The dynamic calculation based on periodInMillis is effectively ignored.


Now, let's swap 500L and 50L and see how the logic changes completely.

this.sleep[i] = Math.min(Math.max(periodInMillis[i]/10, 50L), 500L);

Reevaluate this version from the inside out:

  • Inner Part: Math.max(periodInMillis[i]/10, 50L)
    This part now says: "Calculate 10% of the period, but if that's less than 50, use 50 instead."
    This establishes a minimum sleep time (a floor) of 50ms. The sleep interval will never be shorter than 50ms, preventing the thread from busy-waiting with excessively short sleeps.

  • Outer Part: Math.min(innerResult, 500L)
    This part now says: "Take the result from the inner part (which is always >= 50) and compare it to 500. Return the smaller of the two."
    This establishes a maximum sleep time (a ceiling) of 500ms. This prevents the thread from becoming unresponsive for very long periods if a large periodInMillis is configured.

periodInMillis Config periodInMillis / 10 Original sleep Value (Flawed) Corrected sleep Value (Fixed) Explanation of Fix
200 (e.g., 5 tps/sec) 20 min(max(20, 500), 50) -> 50 min(max(20, 50), 500) -> 50 The floor of 50ms is correctly applied.
1000 (e.g., 100 tps/sec) 100 min(max(100, 500), 50) -> 50 min(max(100, 50), 500) -> 100 The dynamic 10% calculation is now used.
10000 (e.g., 1 tps/sec) 1000 min(max(1000, 500), 50) -> 50 min(max(1000, 50), 500) -> 500 The ceiling of 500ms is correctly applied.

In my opinion, by swapping the two values, the ThroughputControl class is fixed to behave as intended: using a sensible, adaptive polling delay that scales with the configured throughput while remaining within safe operational bounds.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions