Version 4 of Exponential Backoff Delay

Updated 2016-09-02 18:52:50 by Napier

Exponential Backoff Delay

Napier / Dash Automation, LLC

So I needed an exponential backoff delay for reconnecting to our Websocket Server when our servers go down. I decided to implement it using a simple coroutine and the "redelay" command (reconnect delay). Exponential Backoff is used to schedule reconnects to a server so that when your server connection is re-established every instance of your scripts won't reconnect at the same exact time. If you want to learn more I found How to Reconnect Web Sockets in a Realtime Web App without Flooding the Server to be very helpful.

Basically it will generate a delay in ms for which is a random number between 1 second and the maximum delay. Each time you call the coroutine it will increase the maximum and return a new delay to use. You can set a name for the redelay or call it normally. You can also set the maximum seconds (default is 30) by using the second argument.

namespace eval redelay { variable count 0 }

proc redelay {  {name {}} {max 30} } {
  if {$name eq {}} { append name ::redelay::task [incr ::redelay::count] }
  return [coroutine $name ::redelay::delay $max]
}

proc ::redelay::delay { max } {
  yield [info coroutine]
  set attempts 1
  while 1 {
    set interval [expr { min($max, (pow(2, $attempts) - 1)) * 1000 }]
    set delay [expr { int(rand()*($interval-1+1)+1) }]
    incr attempts
    if {[yield $delay] ne {}} { return }
  }
}

Here is an example of it being used (your delays will vary from the ones shown here since it is using random)

set d [redelay]    ; # ::redelay::task1
puts [$d]             ; # 566
puts [$d]             ; # 2071
puts [$d]             ; # 1303
puts [$d]             ; # 5375
puts [$d]             ; # 24724
puts [$d]             ; # 9369
puts [$d]             ; # 11873
puts [$d]             ; # 4104
$d break