• Stars
    star
    133
  • Rank 272,600 (Top 6 %)
  • Language
    Erlang
  • License
    MIT License
  • Created over 11 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Simple exponential backoffs in Erlang

Backoff

Backoff is an Erlang library to deal with exponential backoffs and timers to be used within OTP processes when dealing with cyclical events, such as reconnections, or generally retrying things.

Compiling

rebar3 compile

Running Tests

Tests are implemented as a basic PropEr property-based test suite. Running them requires getting PropEr for the project. The following command line does everything needed:

$ rebar3 as test proper

Modes of Operation

Backoff can be used in 3 main ways:

  1. a simple way to calculate exponential backoffs
  2. calculating exponential backoffs with caps and state tracking
  3. using it to fire timeout events

Simple Backoffs

Simple backoffs work by calling the functions increment/1-2. The function with one argument will grow in an unbounded manner:

1> backoff:increment(1).
2
2> backoff:increment(backoff:increment(1)).
4
3> backoff:increment(backoff:increment(backoff:increment(1))).
8

The version with 2 arguments specifies a ceiling to the value:

4> backoff:increment(backoff:increment(backoff:increment(2))).
16
5> backoff:increment(backoff:increment(backoff:increment(2)), 10).
10

Simple Backoffs with jitter

Jitter based incremental backoffs increase the back off period for each retry attempt using a randomization function that grows exponentially. They work by calling the functions rand_increment/1-2. The function with one argument will grow in an unbounded manner:

1> backoff:rand_increment(1).
3
2> backoff:rand_increment(backoff:rand_increment(1)).
7
3> backoff:rand_increment(backoff:rand_increment(backoff:rand_increment(1))).
19
4> backoff:rand_increment(backoff:rand_increment(backoff:rand_increment(1))).
14
5> backoff:rand_increment(backoff:rand_increment(backoff:rand_increment(1))).
17

The version with 2 arguments specifies a ceiling to the value. If the delay is close to the ceiling the new delay will also be close to the ceiling and may be less than the previous delay.

6> backoff:rand_increment(backoff:rand_increment(backoff:rand_increment(2))).
21
7> backoff:rand_increment(backoff:rand_increment(backoff:rand_increment(2)), 10).
10

State Backoffs

State backoffs keep track of the current value, the initial value, and the maximal value for you. A backoff of that kind is initialized by calling init(Start,Max) and returns an opaque data type to be used with get/1 (fetches the current timer value), fail/1 (increments the value), and succeed/1 (resets the value):

6> B0 = backoff:init(2, 10).
...
7> {_, B1} = backoff:fail(B0).
{4, ...}
8> backoff:get(B1).
4
9> {_, B2} = backoff:fail(B1).
{8, ...}
10> {_, B3} = backoff:fail(B2).
{10, ...}
11> {_, _} = backoff:fail(B3).
{10, ...}

And here we've hit the cap with the failures. Now to succeed again:

12> {_, B4} = backoff:succeed(B3).
{2, ...}
13> backoff:get(B4).
2

That way, backoffs carry all their relevant state.

If what you want are unbound exponential backoffs, you can initiate them with:

14> backoff:init(Start, 'infinity').

And still use them as usual. The increments will have no upper limit.

State Backoffs with jitter

You can enable a jitter based incremental backoff by calling type/2 that swaps the state of the backoff:

1> B0 = backoff:init(2, 30).
{backoff,2,30,2,normal,undefined,undefined}
2> B1 = backoff:type(B0, jitter).
{backoff,2,30,2,jitter,undefined,undefined}
3> {_, B2} = backoff:fail(B1).
{7, ...}
4> {_, B3} = backoff:fail(B2).
{12, ...}

Calling type/2 with argument normal will swap the backoff state back to its default behavior:

5> B4 = backoff:type(B3, normal).
{backoff,2,30,12,normal,undefined,undefined}
6> {_, B5} = backoff:fail(B4).
{24, ...}

Timeout Events

A very common usage for exponential backoffs are with timer events, to be used when driving reconnections or retries to certain sources. Most implementations of this will call erlang:start_timer(Delay, Dest, Message) to do this, and re-use the same values all the time.

Given we want Backoff to carry us the whole way there, additional arguments can be given to the init function to deal with such state and fire events whenever necessary. We first initialize the backoff with init(Start, Max, Dest, Message):

1> B = backoff:init(5000, 20000, self(), hello_world).
...

Then by entering:

2> backoff:fire(B). timer:sleep(2500), flush(). timer:sleep(3000), flush().

and pressing enter, the following sequence of events will unfold:

3> backoff:fire(B). timer:sleep(2500), flush(). timer:sleep(3000), flush().
#Ref<0.0.0.719>
4> timer:sleep(2500), flush(). timer:sleep(3000), flush().
ok
5> timer:sleep(3000), flush().
Shell got {timeout,#Ref<0.0.0.719>,hello_world}
ok

Showing that backoff:fire/1 generates a new timer, and returns the timer reference. This reference can be manipulated with erlang:cancel_timer(Ref) and erlang:read_timer(Ref).

The shell then sleeps (2000 ms), receives nothing, then sleeps some more (3000 ms) and finally receives the timeout event as a regular Erlang timeout message.

Do note that Backoff will not track the timer references given there can be enough use cases with multiple timers, event cancellation, and plenty of other things that can happen with them. Backoff makes it easy to fire them for the right interval, but it is not a wrapper around Erlang timers for all operations.

Changelog

  • 1.1.6: fix compile regexes since darwin version 17.5 would be confused with OTP 17.x
  • 1.1.5: move proper plugin to test profile to avoid build warnings on newer Erlangs
  • 1.1.4: fix dialyzer warnings, update doc
  • 1.1.3: switch to package version of PropEr plugin to avoid mix conflicts
  • 1.1.2: eliminate compilation warnings
  • 1.1.1: corrections to incremental backoff
  • 1.1.0: added jitter based incremental backoff
  • 1.0.0: initial commit stable for over a year

More Repositories

1

recon

Collection of functions and scripts to debug Erlang in production.
Erlang
1,349
star
2

erlang-history

Hacks to add shell history to Erlang's shell
Erlang
495
star
3

pobox

External buffer processes to protect against mailbox overflow in Erlang
Erlang
317
star
4

vmstats

tiny Erlang app to generate information on the Erlang VM
Erlang
253
star
5

dispcount

Erlang task dispatcher based on ETS counters.
Erlang
210
star
6

erlpass

A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever.
Erlang
164
star
7

merklet

Merkle Trees for data replication in Erlang
Erlang
78
star
8

recon_demo

Playground for recon, for practice and demos.
Erlang
64
star
9

sups

PropEr model helper library to validate implementations of supervisor trees
Erlang
63
star
10

zippers

A library for functional zipper data structures in Erlang. Read more on zippers @ http://ferd.ca/yet-another-article-on-zippers.html
Erlang
54
star
11

flatlog

A custom formatter for the Erlang logger application that turns maps into single line text logs
Erlang
52
star
12

ReVault

ReVault is a peer-to-peer self-hosted file synchronization project.
Erlang
50
star
13

cth_readable

Common Test hooks for more readable logs
Erlang
49
star
14

dandelion

A weed is a plant considered undesirable in a particular situation, "a plant in the wrong place". Taxonomically, the term "weed" has no botanical significance, because a plant that is a weed in one context is not a weed when growing in a situation where it is wanted.
Erlang
49
star
15

lrw

Lowest Random Weight hashing for neatly rebalancing hashes
Erlang
45
star
16

simhash

Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data.
Erlang
43
star
17

bertconf

Make ETS tables out of statc BERT files that are auto-reloaded
Erlang
41
star
18

slider

A WxErlang application to generate slidesets.
Erlang
39
star
19

rebar3_proper

Run PropEr test suites with rebar3
Erlang
37
star
20

batchio

io:format middle-man that buffers and batches output sent to the io server for better throughput
Erlang
36
star
21

dlhttpc

dispcount-based lhttpc fork for massive amounts of requests to limited endpoints
Erlang
36
star
22

erl_crashdump_analyzer

shell script to analyze Erlang crash dumps and find some (generally) useful information.
Shell
30
star
23

hairnet

An Erlang library wrapping AES-GCM (AEAD) crypto in a Fernet-like interface
Erlang
29
star
24

howistart-erlang1-code

Code for my tutorial on howistart.org
Erlang
25
star
25

useragent

Identify browsers and OSes from user agent strings, in Erlang
Erlang
25
star
26

hubble

create, read, and update deep Erlang data structures, accessible through explicit paths.
Erlang
18
star
27

cth_retry

Common Test hooks to retry the last failing cases // Now built in Rebar3
Erlang
14
star
28

cascading-failures

crappy bit of Erlang code whose sole purpose is to crash repeatedly.
Erlang
12
star
29

my-finger

Just waiting for pull requests
11
star
30

rebar3_shellrpc

A plugin to send commands to a running rebar3 shell
Erlang
10
star
31

alias_transform

A parse transform to introduce module aliasing into Erlang code
Erlang
10
star
32

blogerl

My own blog engine. It's been held together with duct tape since 2010
HTML
10
star
33

tend

The Erl Next Door -- a useful platform with which we can quickly load dependencies for tutorials or demonstrations online, and letting people try code as they see fit.
Erlang
9
star
34

erl_subgraph_compile

A rebar plugin to only do partial re-builds of some files without any safety checks.
Erlang
9
star
35

calcalc

Calendrical Calculations; Erlang port of Dershowitz & Reingold's algorithms.
Erlang
7
star
36

bitarray

NIF to replace HiPE bitarray functions
JavaScript
6
star
37

start_wrap

Dumb Wrapper to make full releases possible in Erlang with a 'main' loop
Erlang
4
star
38

rebar3_todo

A rebar3 plugin that scans source code for TODO notes
Erlang
4
star
39

interclock

Experimental project to write an Erlang database app using Interval Tree Clocks. NO GUARANTEES EVER.
Erlang
4
star
40

rebar3-alias

Rebar3 Alias Plugin
Erlang
4
star
41

advent-of-code-2021

Trying the advent of code 2021 in Awk
Awk
3
star
42

erl-loadbalance-benchmarks

Erlang
3
star
43

trx

A rebar plugin to export Erlang test data into Visual Studio test format (.trx files)
Erlang
3
star
44

incl_chk

a demo repo for a forum discussion
Erlang
2
star
45

peeranha

Experimental master-to-master DB using ITCs
Erlang
2
star
46

cowboyku

Cowboy fork to be used with Heroku's proxy library
Erlang
1
star