Skip to content

Commit 056d9c6

Browse files
committed
Improve rate-limiting experience
1 parent 42379fe commit 056d9c6

4 files changed

Lines changed: 13 additions & 6 deletions

File tree

prod-config.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,4 @@ required_role = "Organisers"
6666

6767
[animals]
6868
channel_name = "animal-appreciation"
69-
cooldown_seconds = 10
69+
cooldown_seconds = 30

src/europython_discord/animals/cog.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ async def post_animal_picture(self, animal: str, ctx: commands.Context) -> None:
5353
await ctx.send(f"This command can only be used in {channel.mention}.")
5454
return
5555
if self._rate_limiter.is_rate_limited(ctx.author.id):
56-
await ctx.send("You are being rate limited. Please try again later.")
56+
seconds_to_cooldown = self._rate_limiter.get_seconds_until_cooldown(ctx.author.id)
57+
await ctx.send(
58+
f"Sorry, you are being rate-limited. "
59+
f"Try again in {seconds_to_cooldown:.0f} seconds."
60+
)
5761
return
5862

5963
provider = random.choice(self._providers[animal]) # noqa: S311 suspicious-non-cryptographic-random-usage
@@ -71,7 +75,6 @@ async def post_animal_picture(self, animal: str, ctx: commands.Context) -> None:
7175
f"Failed to fetch {animal} picture. "
7276
f"If this happens repeatedly, please report it."
7377
),
74-
ephemeral=True,
7578
)
7679
return
7780

src/europython_discord/animals/rate_limiter.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ def is_rate_limited(self, user_id: int) -> bool:
1515
timeout_end = last_usage + self._cooldown_seconds
1616
return self.get_current_timestamp() < timeout_end
1717

18+
def get_seconds_until_cooldown(self, user_id: int) -> float:
19+
last_usage = self._last_usage_by_user_id.get(user_id, 0)
20+
timeout_end = last_usage + self._cooldown_seconds
21+
return max(0, timeout_end - self.get_current_timestamp())
22+
1823
def register_usage(self, user_id: int) -> None:
1924
self._last_usage_by_user_id[user_id] = self.get_current_timestamp()
2025

tests/animals/test_cog.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,12 @@ async def test_rate_limiting() -> None:
9494
ctx_1.send.assert_awaited_once()
9595
assert "embed" in ctx_1.send.call_args.kwargs
9696

97-
# second call with same user - rate limited, ephemeral error message
97+
# second call with same user
9898
ctx_2 = create_fake_context()
9999
await cog.post_animal_picture(DEFAULT_ANIMAL, ctx=ctx_2)
100100
ctx_2.send.assert_awaited_once()
101101
(message,) = ctx_2.send.call_args.args
102-
assert message == "You are being rate limited. Please try again later."
102+
assert message == "Sorry, you are being rate-limited. Try again in 10 seconds."
103103

104104

105105
async def test_rate_limiting_different_user() -> None:
@@ -163,4 +163,3 @@ async def generate_image(self) -> AnimalImage | None:
163163
assert message == (
164164
f"Failed to fetch {DEFAULT_ANIMAL} picture. If this happens repeatedly, please report it."
165165
)
166-
assert ctx.send.call_args.kwargs.get("ephemeral") is True

0 commit comments

Comments
 (0)