module Expert:sig
..end
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.
hopper_to_bucket_rate_per_sec
bounds the maximum rate at which tokens fall from
the hopper into the bucket where they can be taken.bucket_size
bounds the number of tokens that the lower bucket can hold. This
corresponds to the maximum burst in a standard token bucket setup.initial_hopper_level
sets the number of tokens placed into the hopper when the
Limiter
is created.initial_bucket_level
sets the number of tokens placed into the bucket when the
Limiter
is created. If this amount exceeds the bucket size it will be silently
limited to bucket_size
.
initial_hopper_level + initial_bucket_level
should be bounded and clients
hold tokens for the duration of their work.hopper_to_bucket_rate_per_sec
should be
infinite but the number of tokens in the system initial_hopper_level +
initial_bucket_level
should be bounded. Workers also need to take care to return
tokens to the system.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 ]
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 ]
try_take t ~now n
succeeds iff in_bucket t ~now >= n
.val return_to_hopper : Limiter.t -> now:Time.t -> float -> unit
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
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