Up
# Module Expert

#####
expert operations

### Signature

val
create_exn : now:Time.t -> hopper_to_bucket_rate_per_sec:float Infinite_or_finite.t -> bucket_limit:float -> in_flight_limit:float Infinite_or_finite.t -> initial_bucket_level:float -> initial_hopper_level:float Infinite_or_finite.t -> 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_limit`

bounds the number of tokens that the lower bucket can hold. This corresponds to the maximum burst in a standard token bucket setup.

`in_flight_limit`

bounds the number of tokens that can be in flight. This corresponds to a running job limit/throttle.

`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_limit`

.

These tunables can be combined in several ways:

- to produce a simple rate limiter, where the hopper is given an infinite number of tokens and clients simply take tokens as they are delivered to the bucket.

- to produce a rate_limiter that respects jobs that are more than instantaneous. In
this case
`initial_hopper_level + initial_bucket_level`

should be bounded and clients hold tokens for the duration of their work.

- to produce a throttle that doesn't limit the rate of jobs at all, but always keeps a
max of n jobs running. In this case
`hopper_to_bucket_rate_per_sec`

should be infinite but`in_flight_limit`

should be bounded to the upper job rate.

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.

`try_take`

to actually attempt to take the
tokens.

`try_take t ~now n`

succeeds iff `in_bucket t ~now >= n`

.

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.