Module Limiter.Expert

module Expert: sig .. end
expert operations


val create_exn : now:Time.t ->
hopper_to_bucket_rate_per_sec:float Limiter.Infinite_or_finite.t ->
bucket_size:float ->
initial_bucket_level:float ->
initial_hopper_level:float Limiter.Infinite_or_finite.t -> Limiter.t
- time is the reference time that other time accepting functions will use when they adjust now. It is almost always correct to set this to Time.now.

These tunables can be combined in several ways:

In all cases above throttling and rate limiting combine nicely when the unit of work for both is the same (e.g. one token per message). If the unit of work is different (e.g. rate limit base on a number of tokens equal to message size, but throttle base on simple message count) then a single t probably cannot be used to get the correct behavior, and two instances should be used with tokens taken from both.
val tokens_may_be_available_when : Limiter.t ->
now:Time.t ->
float ->
[ `At of Time.t
| `Never_because_greater_than_bucket_size
| `When_return_to_hopper_is_called ]
returns the earliest time when the requested number of tokens could possibly be delivered. There is no guarantee that the requested number of tokens will actually be available at this time. You must call try_take to actually attempt to take the tokens.
val try_take : Limiter.t ->
now:Time.t ->
float -> [ `Asked_for_more_than_bucket_size | `Taken | `Unable ]
attempts to take the given number of tokens from the bucket. try_take t ~now n succeeds iff in_bucket t ~now >= n.
val return_to_hopper : Limiter.t -> now:Time.t -> float -> unit
return the given number of tokens to the hopper. These tokens will fill the tokens available to try_take at the fill_rate. Note that if return is called on more tokens then have actually been removed, this can cause the number of concurrent jobs to exceed max_concurrent_jobs.

Note that, due to rounding issues, one should only return precisely the number of tokens that were previously taken. Returning a sum of different values taken previously may or may not work precisely, depending on the specific floating point numbers used.

val set_hopper_to_bucket_rate_per_sec_exn : Limiter.t -> now:Time.t -> float Limiter.Infinite_or_finite.t -> unit
val set_token_target_level_exn : Limiter.t -> now:Time.t -> float Limiter.Infinite_or_finite.t -> unit
sets the target token level for the limiter going forward.

If the system has more tokens than the new target already in it then tokens will be removed (first from the hopper, and then from the bucket) to meet the new maximum. If the target cannot be satisfied by removing tokens from the bucket and hopper (i.e. in_flight is, itself, greater than the new target) the hopper and the bucket will be emptied, and future calls to return_to_hopper will drop tokens until the total number of tokens in the system matches the new target.

Conversely, if in_hopper + in_bucket + in_flight is less than the new target tokens will be added to the hopper such that in_hopper + in_bucket + in_flight = the new max.

NOTE: you should consider calling set_bucket_size after calling set_token_target_level as the bucket_size is often set to a number related to the number of tokens in the system.

val set_bucket_size_exn : Limiter.t -> now:Time.t -> float -> unit