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
}
// Attempt attempts to perform a request for an id and returns whether it was
// successful or not.