feat: add order-take rate limit to prevent spam#828
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
WalkthroughThis PR introduces per-user order-take rate limiting by tracking take counts and enforcing configurable cooldowns. It adds database fields for state tracking, environment variables for thresholds, enforcement logic in order handlers, localized user messaging, and state reset on order completion across ten languages. ChangesOrder-take rate limiting
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Possibly related issues
Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
bot/modules/orders/takeOrder.ts (2)
86-97:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftPersisting the user counter before order save can over-penalize users.
At Line 86/147,
incrementTakeOrderCount(user)is saved before Line 96/153order.save(). If order persistence fails, the user still gets count/cooldown updates for a take that never completed. This should be one atomic unit (or at least update the counter only after order save succeeds).Also applies to: 147-153, 194-195
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@bot/modules/orders/takeOrder.ts` around lines 86 - 97, The incrementTakeOrderCount(user) call is executed before persisting the order, which will penalize the user if order.save() fails; move the incrementTakeOrderCount(user) to after a successful await order.save() (or wrap both operations in a DB transaction if supported) so the counter/cooldown is only updated once order.status, order.seller_id, taken_at and order.random_image have been persisted; adjust the same pattern wherever incrementTakeOrderCount appears (lines referencing incrementTakeOrderCount, order.save, generateRandomImage, and order.status) to ensure counter updates occur post-save or inside the same atomic transaction.
62-63:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftPer-order mutex does not protect per-user counter updates.
At Line 62 and Line 114, locking is keyed by
orderId, so the same user can take different orders concurrently and race ontake_order_countvia Line 194user.save(). Use an atomic DB update ($inc+ conditional cooldown update) or add a per-user lock to avoid lost updates.Also applies to: 114-115, 184-195
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@bot/modules/orders/takeOrder.ts` around lines 62 - 63, The per-order mutex (PerOrderIdMutex.instance.runExclusive keyed by orderId) does not prevent concurrent updates to the same user's take_order_count because different orders for the same user can run concurrently; replace or augment this by performing an atomic database update (use a single update with $inc on take_order_count plus conditional update of the cooldown fields via a conditional operator/aggregation pipeline) or acquire a per-user lock (e.g., PerUserIdMutex.instance.runExclusive keyed by user.id) around the critical section that reads/modifies user and calls user.save(); locate uses of PerOrderIdMutex.instance.runExclusive, the user.save() call and the take_order_count update and change them to either an atomic DB operation or wrap the user mutation in a per-user mutex to prevent lost updates.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@bot/modules/orders/takeOrder.ts`:
- Around line 170-182: The cooldown check is leaving stale state in
user.take_order_count when user.take_order_cooldown_until is in the past; update
the logic in the function in takeOrder.ts that checks
user.take_order_cooldown_until to first detect an expired timestamp and
reset/clear user.take_order_count and user.take_order_cooldown_until before
proceeding, then persist/update the user as needed; continue to call
messages.orderTakeRateLimitMessage(ctx, user, user.take_order_cooldown_until)
only when the cooldown is still in the future. Also apply the same
expired-timestamp reset to the similar block referenced around the 188–193
region.
- Around line 185-186: The env parsing for rate-limit config (maxOrdersTake and
cooldownHours in takeOrder.ts) can yield NaN or non-positive values and disable
cooldown logic; after parsing parseInt(process.env.MAX_ORDERS_TAKE || '10') and
parseInt(process.env.ORDER_TAKE_COOLDOWN_HOURS || '24'), validate each parsed
value (maxOrdersTake and cooldownHours) with Number.isFinite/Number.isInteger
and ensure they are > 0, otherwise reset to safe defaults (e.g., 10 for
maxOrdersTake and 24 for cooldownHours) and optionally clamp to sensible bounds;
update any usages that rely on these variables (e.g., rate-limit checks like
count >= cooldownHours) to use the validated values.
---
Outside diff comments:
In `@bot/modules/orders/takeOrder.ts`:
- Around line 86-97: The incrementTakeOrderCount(user) call is executed before
persisting the order, which will penalize the user if order.save() fails; move
the incrementTakeOrderCount(user) to after a successful await order.save() (or
wrap both operations in a DB transaction if supported) so the counter/cooldown
is only updated once order.status, order.seller_id, taken_at and
order.random_image have been persisted; adjust the same pattern wherever
incrementTakeOrderCount appears (lines referencing incrementTakeOrderCount,
order.save, generateRandomImage, and order.status) to ensure counter updates
occur post-save or inside the same atomic transaction.
- Around line 62-63: The per-order mutex (PerOrderIdMutex.instance.runExclusive
keyed by orderId) does not prevent concurrent updates to the same user's
take_order_count because different orders for the same user can run
concurrently; replace or augment this by performing an atomic database update
(use a single update with $inc on take_order_count plus conditional update of
the cooldown fields via a conditional operator/aggregation pipeline) or acquire
a per-user lock (e.g., PerUserIdMutex.instance.runExclusive keyed by user.id)
around the critical section that reads/modifies user and calls user.save();
locate uses of PerOrderIdMutex.instance.runExclusive, the user.save() call and
the take_order_count update and change them to either an atomic DB operation or
wrap the user mutation in a per-user mutex to prevent lost updates.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 870f3837-70a7-4381-a84d-d62b7257d716
📒 Files selected for processing (15)
.env-samplebot/messages.tsbot/modules/orders/takeOrder.tslocales/de.yamllocales/en.yamllocales/es.yamllocales/fa.yamllocales/fr.yamllocales/it.yamllocales/ko.yamllocales/pt.yamllocales/ru.yamllocales/uk.yamlmodels/user.tsutil/index.ts
Add a rate limit on order taking to prevent spam: users who exceed
MAX_ORDERS_TAKEconsecutive takes without completing an order are temporarily blocked until the cooldown expires or they complete a trade.Summary
MAX_ORDERS_TAKEandORDER_TAKE_COOLDOWN_HOURSenv vars to control the rate limittake_order_countandtake_order_cooldown_untilon the User modelChanges
models/user.ts— new fields:take_order_count,take_order_cooldown_untilbot/modules/orders/takeOrder.ts— rate limit check intakebuyandtakesellutil/index.ts— reset counter on order completion (SUCCESS)bot/messages.ts— neworderTakeRateLimitMessagewith remaining hourslocales/—order_take_rate_limitkey added in all 10 languages.env-sample— documented new env vars with defaults (MAX_ORDERS_TAKE=10,ORDER_TAKE_COOLDOWN_HOURS=24)Summary by CodeRabbit
New Features
Chores