Skip to content

Commit

Permalink
Implement peeking available tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
NelsonVides committed Jan 12, 2024
1 parent feeef34 commit d13c8e6
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 1 deletion.
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,22 @@
`opuntia` is a basic set of tools for traffic shaping for erlang and elixir

It implements the [token bucket algorithm](https://en.wikipedia.org/wiki/Token_bucket).

There are two ways to use it, checking availability a priori or accepting a penalisation.

After creating a bucket
```erl
Bucket = opuntia:new(#{bucket_size => 10, rate => 1, time_unit => millisecond, start_full => true}),
```
you can either consume all tokens queued and see the suggested delay, considering that this might
allow you to consume at once much more than the bucket size:
```erl
{NewShaper, Delay} = opuntia:update(Shaper, 50),
timer:sleep(Delay), %% Will suggest to sleep 40ms
```
or you can first how many tokens are available for you to consume before doing so:
```erl
Allowed = opuntia:peek(Shaper),
consume_tokens(Allowed),
{NewShaper, 0} = opuntia:update(Shaper), %% Will suggest no delay if you were diligent and consume less that adviced
```
10 changes: 9 additions & 1 deletion src/opuntia.erl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
%% @end
-module(opuntia).

-export([new/1, update/2]).
-export([new/1, update/2, peek/1]).

-ifdef(TEST).
-export([create/2, calculate/3, convert_time_unit/3]).
Expand Down Expand Up @@ -83,6 +83,14 @@ new(0) ->
new(Shape) ->
create(Shape, erlang:monotonic_time()).

%% @doc Peek currently available tokens.
-spec peek(shaper()) -> non_neg_integer() | infinity.
peek(none) ->
infinity;
peek(Shaper) ->
{NewShaper, _} = calculate(Shaper, 0, erlang:monotonic_time()),
NewShaper#token_bucket_shaper.available_tokens.

%% @doc Update shaper and return possible waiting time.
%%
%% This function takes the current shaper state, and the number of tokens that have been consumed,
Expand Down
12 changes: 12 additions & 0 deletions test/opuntia_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ groups() ->
[
{throughput_throttle, [sequence],
[
peek_available,
simple_test_no_delay_is_needed,
run_shaper_with_zero_does_not_shape,
run_shaper_without_consuming_does_not_delay,
Expand Down Expand Up @@ -77,6 +78,17 @@ keep_table() ->
%%% Individual Test Cases (from groups() definition)
%%%===================================================================

peek_available(_) ->
Prop = ?FORALL(Shape, shape(),
begin
#{bucket_size := Size} = Shape,
Shaper = opuntia:new(Shape#{start_full => true}),
Peek = opuntia:peek(Shaper),
Val = value_in_range(Peek, 0, Size),
success_or_log_and_return(Val, "shape of ~p was actually requested", [Peek])
end),
run_prop(?FUNCTION_NAME, Prop, 100, 1).

simple_test_no_delay_is_needed(_) ->
Units = [second, millisecond, microsecond, nanosecond, native],
[ simple_test_no_delay_is_needed_for_unit(Unit) || Unit <- Units ].
Expand Down

0 comments on commit d13c8e6

Please sign in to comment.