Author: Tarak Shah
Date: 2018-10-07

# Introduction to ratelimitr

#### Tarak Shah

#### 2018-10-07

## The basics

Use ratelimitr to limit the rate at which functions are called. A rate-limited function that allows `n` calls per `period` will never have a window of time of length `period` that includes more than `n` calls.

    library(ratelimitr)
    f <- function() NULL

    # create a version of f that can only be called 10 times per second
    f_lim <- limit_rate(f, rate(n = 10, period = 1))

    # time without limiting
    system.time(replicate(11, f()))

    ##    user  system elapsed
    ##   0.001   0.000   0.001

    # time with limiting
    system.time(replicate(11, f_lim()))

    ##    user  system elapsed
    ##   0.007   0.000   1.029

## Multiple rates

Published rate limits often have multiple types of limits. Here is an example of limiting a function so that it never evaluates more than 10 times per .1 seconds, but additionally never evaluates more than 50 times per 1 second.

    f_lim <- limit_rate(
        f,
        rate(n = 10, period = .1),
        rate(n = 50, period = 1)
    )

    # 10 calls do not trigger the rate limit
    system.time( replicate(10, f_lim()) )

    ##    user  system elapsed
    ##   0.001   0.000   0.001

    # note that reset does not modify its argument, but returns a new
    # rate-limited function with a fresh timer
    f_lim <- reset(f_lim)
    system.time( replicate(11, f_lim()) )

    ##    user  system elapsed
    ##   0.002   0.000   0.158

    # similarly, 50 calls don't trigger the second rate limit
    f_lim <- reset(f_lim)
    system.time( replicate(50, f_lim()) )

    ##    user  system elapsed
    ##   0.012   0.000   0.560

    # but 51 calls do:
    f_lim <- reset(f_lim)
    system.time( replicate(51, f_lim()) )

    ##    user  system elapsed
    ##   0.013   0.002   1.053

## Multiple functions sharing one (or more) rate limit(s)

To limit a group of functions together, just pass `limit_rate` a list of functions instead of a single function. Make sure the list is named, the names will be how you access the rate-limited versions of the functions:

    f <- function() "f"
    g <- function() "g"
    h <- function() "h"

    # passing a named list to limit_rate
    limited <- limit_rate(
        list(f = f, g = g, h = h),
        rate(n = 3, period = 1)
    )

    # now limited is a list of functions that share a rate limit. examples:
    limited$f()

    ## [1] "f"

    limited$g()

    ## [1] "g"

The new functions are subject to a single rate limit, regardless of which ones are called or in what order they are called.

    # the first three function calls should not trigger a delay
    system.time(
        {limited$f(); limited$g(); limited$h()}
    )

    ##    user  system elapsed
    ##   0.001   0.000   0.001

    limited <- reset(limited)

    # but to evaluate a fourth function call, there will be a delay
    system.time({
        limited$f()
        limited$g()
        limited$h()
        limited$f()
    })

    ##    user  system elapsed
    ##   0.001   0.000   1.059