speedbump.go
func (r *RateLimiter) Attempt(id string) (bool, error) {
	// Create hash from id
	hash := r.hasher.Hash(id)

	// Get value for hash in Redis. If redis.Nil is returned, key does not
	// exist.
	exists := true

	val, err := r.redisClient.Get(hash).Result()
	if err != nil {
		if err == redis.Nil {
			// Key does not exist. See: http://redis.io/commands/GET
			exists = false
		} else {
			return false, err
		}
	}

	// If key exists and is >= max requests, return false.
	if exists {
		intVal, err := strconv.ParseInt(val, 10, 64)
		if err != nil {
			return false, err
		}

		if intVal >= r.max {
			return false, nil
		}
	}

	// Otherwise, increment and expire key for hasher.Duration(). Note, we call
	// Expire even when key already exists to avoid race condition where key
	// expires between prior existence check and this Incr call.
	//
	// See: http://redis.io/commands/INCR
	// See: http://redis.io/commands/INCR#pattern-rate-limiter-1
	err = r.redisClient.Watch(func(rx *redis.Tx) error {
		_, err := rx.Pipelined(func(pipe *redis.Pipeline) error {
			if err := pipe.Incr(hash).Err(); err != nil {
				return err
			}

			return pipe.Expire(hash, r.hasher.Duration()).Err()
		})

		return err
	})

	if err != nil {
		return false, err
	}

	return true, nil
}
func (r *RateLimiter) Attempt(id string) (bool, error) {
	// Create hash from id
	hash := r.hasher.Hash(id)

	// Get value for hash in Redis. If redis.Nil is returned, key does not
	// exist.
	exists := true

	val, err := r.redisClient.Get(hash).Result()
	if err != nil {
		if err == redis.Nil {
			// Key does not exist. See: http://redis.io/commands/GET
			exists = false
		} else {
			return false, err
		}
	}

	// If key exists and is >= max requests, return false.
	if exists {
		intVal, err := strconv.ParseInt(val, 10, 64)
		if err != nil {
			return false, err
		}

		if intVal >= r.max {
			return false, nil
		}
	}

	// Otherwise, increment and expire key for hasher.Duration(). Note, we call
	// Expire even when key already exists to avoid race condition where key
	// expires between prior existence check and this Incr call.
	//
	// See: http://redis.io/commands/INCR
	// See: http://redis.io/commands/INCR#pattern-rate-limiter-1
	err = r.redisClient.Watch(func(rx *redis.Tx) error {
		_, err := rx.Pipelined(func(pipe *redis.Pipeline) error {
			if err := pipe.Incr(hash).Err(); err != nil {
				return err
			}

			return pipe.Expire(hash, r.hasher.Duration()).Err()
		})

		return err
	})

	if err != nil {
		return false, err
	}

	return true, nil
}
func ( r * RateLimiter ) Attempt ( id string ) ( bool , error ) { // Create hash from id hash := r . hasher . Hash ( id ) // Get value for hash in Redis. If redis.Nil is returned, key does not // exist. exists := true val , err := r . redisClient . Get ( hash ) . Result ( ) if err != nil { if err == redis . Nil { // Key does not exist. See: http://redis.io/commands/GET exists = false } else { return false , err } } // If key exists and is >= max requests, return false. if exists { intVal , err := strconv . ParseInt ( val , 10 , 64 ) if err != nil { return false , err } if intVal >= r . max { return false , nil } } // Otherwise, increment and expire key for hasher.Duration(). Note, we call // Expire even when key already exists to avoid race condition where key // expires between prior existence check and this Incr call. // // See: http://redis.io/commands/INCR // See: http://redis.io/commands/INCR#pattern-rate-limiter-1 err = r . redisClient . Watch ( func ( rx * redis . Tx ) error { _ , err := rx . Pipelined ( func ( pipe * redis . Pipeline ) error { if err := pipe . Incr ( hash ) . Err ( ) ; err != nil { return err } return pipe . Expire ( hash , r . hasher . Duration ( ) ) . Err ( ) } ) return err } ) if err != nil { return false , err } return true , nil }
// Attempt attempts to perform a request for an id and returns whether it was
// successful or not.
Attempt attempts to perform a request for an id and returns whether it was successful or not .