Skip to content

Add temporary per-day user throttling #392

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
May 3, 2023
Merged

Conversation

molly-moen
Copy link
Contributor

As part of Java Lab Eval Mode, we want to add back in daily user throttling, but have it not block the user forever, only until they are back under the limit. In this PR I:

  • Converted our turned-off daily throttling to be this temporary model, and added a new key USER_BLOCKED_TEMPORARY that we will send if the user reaches their limit in a day.
  • Updated the near limit message to include the interval and whether this is a permanent or temporary block.
  • Updated our daily and hourly limits such that if the limit is 0, there is no limit. We need this because we don't want hourly limits on javabuilder-demo, and we don't want a daily limit on production javabuilder (for now).

This PR cannot be merged until the corresponding code.org PR has been merged and deployed.

Copy link
Contributor

@sanchitmalhotra126 sanchitmalhotra126 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

)
limit_per_hour = ENV['limit_per_hour'].to_i
# A limit of 0 means there is no limit.
if limit_per_hour > 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: early return false if limit_per_hour == 0?

Comment on lines 36 to +39
near_limit_detail = get_user_near_hourly_limit_detail(hourly_usage_response.count)
if !near_limit_detail
near_limit_detail = get_user_near_daily_limit_detail(daily_usage_response.count)
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the way our limits set up, seems like there's no way for a user to be near both an hourly limit and a daily limit - but if there was, I guess we're prioritizing the hourly limit warning? Seems fine to me, just wanted to clarify

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would a downside of that be a user receiving a "hourly limit" warning message, so they come back in an hour only to receive the "daily limit" message on their first attempt? Only matters if the messages are unique.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though, the hourly limit triggers a permanent block, so it does make sense that it should go first.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good questions. Yes, in our prod environments only one of these will be set (demo has a daily limit, prod has an hourly). But if we want both, my presumption was the hourly would be much lower than the daily and therefore the user would hit that first. And the fact that hourly triggers the permanent block means it is more important to message. The messages to the user are unique--they say what the time frame was (hour or day) and if the block is permanent.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels like overkill for now to make some combined message given we won't show it to users, but it could be a follow-up if we think we'll enable both limits at some point.

if count <= limit && count >= (limit - NEAR_LIMIT_BUFFER)
return {remaining: limit - count}
def get_user_near_limit_detail(count, limit, period, lockout_type)
if limit > 0 && count <= limit && count >= (limit - NEAR_LIMIT_BUFFER)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: if we want to be super clear, maybe we can save 0 as a constant like "NO_LIMIT" or something, and check limit != NO_LIMIT here? The 0 is documented well enough in the template so maybe not necessary

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since this is slightly hacky, it doesn't hurt to be super clear. I'll update this

Copy link
Contributor

@cat5inthecradle cat5inthecradle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template and config changes look good.

@@ -11,6 +11,7 @@ class TokenValidator
USER_REQUEST_RECORD_TTL_SECONDS = 25 * ONE_HOUR_SECONDS
TEACHER_ASSOCIATED_REQUEST_TTL_SECONDS = 25 * ONE_HOUR_SECONDS
NEAR_LIMIT_BUFFER = 10
NO_LIMIT = 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any cases where we would set the limit to zero intending to "shut off" access? i.e. I think our guidance in a DDOS is to set reserved concurrency to zero. Any reason we'd do that here too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if we set reserved concurrency to 0 that would cover shutting off access. If we want to severely limit access we could set limits to 1. For hourly limit that would probably be more trouble than it's worth, because we would have to then go unblock everyone.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just had a thought (not blocking). Does this take negative numbers? -1 seems like a pretty common "no limit" key that's less likely to have us run into issues in the future.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense too (using -1), but if we used that, we'd probably want to make 0 have some predictable defined behavior (automatic rejection with a 'limit exceed' error).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try it out, the easiest way to try it out is by committing to auto-deploy to my dev instance, so there may be a little churn on this pr in the meantime.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-1 works and I agree it's a bit cleaner, so let's go with that!

@molly-moen molly-moen merged commit 60bb9af into main May 3, 2023
@molly-moen molly-moen deleted the molly-demo-user-throttle branch May 3, 2023 20:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants