slidingwindow: github.com/RussellLuo/slidingwindow Index | Examples | Files | Directories

package slidingwindow

import "github.com/RussellLuo/slidingwindow"

Code:

lim, _ := sw.NewLimiter(time.Second, 10, func() (sw.Window, sw.StopFunc) {
    // NewLocalWindow returns an empty stop function, so it's
    // unnecessary to call it later.
    return sw.NewLocalWindow()
})

ok := lim.Allow()
fmt.Printf("ok: %v\n", ok)

Output:

ok: true

Code:

package main

import (
    "fmt"
    "strconv"
    "time"

    sw "github.com/RussellLuo/slidingwindow"
    "github.com/go-redis/redis"
)

// RedisDatastore is a reference implementation, which can be used directly
// if you happen to use go-redis.
type RedisDatastore struct {
    client *redis.Client
    ttl    time.Duration
}

func newRedisDatastore(client *redis.Client, ttl time.Duration) *RedisDatastore {
    return &RedisDatastore{client: client, ttl: ttl}
}

func (d *RedisDatastore) fullKey(key string, start int64) string {
    return fmt.Sprintf("%s@%d", key, start)
}

func (d *RedisDatastore) Add(key string, start, value int64) (int64, error) {
    k := d.fullKey(key, start)
    c, err := d.client.IncrBy(k, value).Result()
    if err != nil {
        return 0, err
    }
    // Ignore the possible error from EXPIRE command.
    d.client.Expire(k, d.ttl).Result() // nolint:errcheck
    return c, err
}

func (d *RedisDatastore) Get(key string, start int64) (int64, error) {
    k := d.fullKey(key, start)
    value, err := d.client.Get(k).Result()
    if err != nil {
        if err == redis.Nil {
            // redis.Nil is not an error, it only indicates the key does not exist.
            err = nil
        }
        return 0, err
    }
    return strconv.ParseInt(value, 10, 64)
}

func main() {
    size := time.Second
    store := newRedisDatastore(
        redis.NewClient(&redis.Options{
            Addr: "localhost:6379",
        }),
        2*size, // twice of window-size is just enough.
    )

    lim, stop := sw.NewLimiter(size, 10, func() (sw.Window, sw.StopFunc) {
        return sw.NewSyncWindow(store, "test", true, time.Second)
    })
    defer stop()

    ok := lim.Allow()
    fmt.Printf("ok: %v\n", ok)

}

Index

Examples

Package Files

slidingwindow.go windows.go

func NewLimiter Uses

func NewLimiter(size time.Duration, limit int64, newWindow NewWindow) (*Limiter, StopFunc)

NewLimiter creates a new limiter, and returns a function to stop the possible sync behaviour within the current window.

func NewLocalWindow Uses

func NewLocalWindow() (Window, StopFunc)

func NewSyncWindow Uses

func NewSyncWindow(store Datastore, key string, blockingSync bool, syncInterval time.Duration) (Window, StopFunc)

NewSyncWindow creates an instance of SyncWindow with the given configurations. Particularly, blockingSync indicates whether to block waiting for each synchronization to complete.

type Datastore Uses

type Datastore interface {
    // Add adds delta to the count of the window represented
    // by start, and returns the new count.
    Add(key string, start, delta int64) (int64, error)

    // Get returns the count of the window represented by start.
    Get(key string, start int64) (int64, error)
}

type Limiter Uses

type Limiter struct {
    // contains filtered or unexported fields
}

func (*Limiter) Allow Uses

func (lim *Limiter) Allow() bool

Allow is shorthand for AllowN(time.Now(), 1).

func (*Limiter) AllowN Uses

func (lim *Limiter) AllowN(now time.Time, n int64) bool

AllowN reports whether n events may happen at time now.

func (*Limiter) Limit Uses

func (lim *Limiter) Limit() int64

Limit returns the maximum events permitted to happen during one window size.

func (*Limiter) SetLimit Uses

func (lim *Limiter) SetLimit(newLimit int64)

SetLimit sets a new Limit for the limiter.

func (*Limiter) Size Uses

func (lim *Limiter) Size() time.Duration

Size returns the time duration of one window size. Note that the size is defined to be read-only, if you need to change the size, create a new limiter with a new size instead.

type LocalWindow Uses

type LocalWindow struct {
    // contains filtered or unexported fields
}

LocalWindow represents a window that ignores sync behavior entirely and only stores counters in memory.

func (*LocalWindow) AddCount Uses

func (w *LocalWindow) AddCount(n int64)

func (*LocalWindow) Count Uses

func (w *LocalWindow) Count() int64

func (*LocalWindow) Reset Uses

func (w *LocalWindow) Reset(s time.Time, c int64)

func (*LocalWindow) Start Uses

func (w *LocalWindow) Start() time.Time

func (*LocalWindow) Sync Uses

func (w *LocalWindow) Sync(now time.Time)

type NewWindow Uses

type NewWindow func() (Window, StopFunc)

NewWindow creates a new window, and returns a function to stop the possible sync behaviour within it.

type StopFunc Uses

type StopFunc func()

StopFunc stops the window's sync behaviour.

type SyncWindow Uses

type SyncWindow struct {
    LocalWindow
    // contains filtered or unexported fields
}

SyncWindow represents a window that will sync counter data to the central datastore asynchronously.

Note that for the best coordination between the window and the synchronizer, the synchronization is not automatic but is driven by the call to Sync. Also there are two sync modes: blocking-sync and non-blocking-sync. In low-concurrency scenarios, you can use the blocking-sync mode for higher accuracy. In other cases (e.g. accuracy is less important than performance, or in high-concurrency scenarios), choose the non-blocking-sync mode instead.

func (*SyncWindow) AddCount Uses

func (w *SyncWindow) AddCount(n int64)

func (*SyncWindow) Reset Uses

func (w *SyncWindow) Reset(s time.Time, c int64)

func (*SyncWindow) Sync Uses

func (w *SyncWindow) Sync(now time.Time)

type Window Uses

type Window interface {
    // Start returns the start boundary.
    Start() time.Time

    // Count returns the accumulated count.
    Count() int64

    // AddCount increments the accumulated count by n.
    AddCount(n int64)

    // Reset sets the state of the window with the given settings.
    Reset(s time.Time, c int64)

    // Sync tries to exchange data between the window and the central
    // datastore at time now, to keep the window's count up-to-date.
    Sync(now time.Time)
}

Window represents a fixed-window.

Directories

PathSynopsis
testutil

Package slidingwindow imports 3 packages (graph) and is imported by 1 packages. Updated 2019-12-04. Refresh now. Tools for package owners.