brandur/redis-cell

Returning Unused Tokens

Closed this issue · 4 comments

I've been utilizing redis-cell for a research project and first and foremost thank you for your work.

I'm in a situation where I want to all or nothing check two different keys that can be throttled. I need to check one, have it pass then check the other and have it also pass before I approve the action. I perform the entire atomic operation via a LUA script.

In the event the second key cl.throttle returns 1 (throttled), is it appropriate to return the first via:

cl.throttle key burst max period -1

Preliminary tests seem to indicate this works, but I'm unsure if this was intentional. Is there a potential fringe case where this would fail or un-optimize key usage?

In the event the second key cl.throttle returns 1 (throttled), is it appropriate to return the first via:

Hm, just to make sure I understand this correctly: if you're just trying to return the result of the first cl.throttle invocation, couldn't you just set that as a variable when it's called and then return that later?

ret1 = cl.throttle ...
ret2 = cl.throttle ...
if ret2 == 1
  return ret1
end

(Or something to that effect.)

Sure, but the token is still consumed from the first bucket since it passed, correct? I don't want the first token consumed if the second one fails.

I put water in the first bucket, then water in the second bucket. If I can't put water in the second bucket, then I want to take the water I put into the first bucket out.

Essentially I want to undo ever calling ret1 = cl.throttle ... if ret2 ==1. Or maybe I can fork this and create a cl.peek to check what cl.throttle would return without consuming a token. Maybe this can be done already by asking for 0 tokens instead of the default 1?

Ah, I see.

Well, the calculation to get a new value when cl.throttle is called is really just basic multiplication and it uses signed numbers all the way through. If it looks like it works by just using a negative value, then that's probably fine to do.

Essentially I want to undo ever calling ret1 = cl.throttle ... if ret2 ==1. Or maybe I can fork this and create a cl.peek to check what cl.throttle would return without consuming a token. Maybe this can be done already by asking for 0 tokens instead of the default 1?

One other alternative is that you can peek today by just passing 0 as the last argument. This case is actually verified in the test suite:

            // Zero-volume request just peeks at the state.
            RateLimitCase::new(12, start + time::Duration::milliseconds(9500), 0, 4,
                time::Duration::seconds(1), time::Duration::seconds(-1), false),

This is perfect then. Since Redis guarantees atomicity during a LUA script, I could peek at both buckets and make a decision there.

Thank you for the quick responses.