Overview
The rate limiting system uses a sliding time-window approach to prevent abuse and ensure fair resource usage. Rate limits are stored in therateLimit database table and enforced at the guard function level before any database operations.
Database Schema
rateLimit Table
Table ID:ratelimit
Database: cric_talk (ID: 695761d00008fd927f78)
Row Security: Disabled (server-side access only)
Columns
| Column | Type | Required | Constraints | Description |
|---|---|---|---|---|
userId | string | Yes | Max 36 chars | User identifier |
activity | string | Yes | Max 36 chars | Action name (e.g., “create_post”) |
windowKey | integer | Yes | - | Time window identifier |
activityCount | integer | Yes | Min: 1, Max: 60 | Number of actions in current window |
Indexes
| Index | Type | Columns | Purpose |
|---|---|---|---|
userid_index | key | userId ASC | Fast user lookups |
activity_index | key | activity ASC | Filter by action type |
windowKey_index | key | windowKey ASC | Time window queries |
createdAt_index | key | $createdAt DESC | Cleanup old entries |
How Rate Limiting Works
1. Window Key Generation
Rate limits use 1-minute time windows. The window key is calculated as:2024-01-15 10:30:00→windowKey: 289534502024-01-15 10:30:59→windowKey: 28953450(same window)2024-01-15 10:31:00→windowKey: 28953451(new window)
2. Activity Tracking
Each action type is tracked separately using a unique activity identifier:| Activity | Rate Limit | Used In Function |
|---|---|---|
create_post | 10/min | posts-guard |
update_post | 10/min | posts-guard |
delete_post | 10/min | posts-guard |
add_comment | 60/min | comments-guard |
update_comment | 60/min | comments-guard |
delete_comment | 60/min | comments-guard |
create_room | 10/min | rooms-guard |
update_room | 10/min | rooms-guard |
delete_room | 10/min | rooms-guard |
create_room_message | 60/min | room-message-guard |
update_room_message | 60/min | room-message-guard |
delete_room_message | 60/min | room-message-guard |
3. Rate Limit Check Flow
Fromfunctions/posts-guard/src/main.js:36-85:
Rate Limit Configuration
Posts Guard (10 requests/minute)
Fromfunctions/posts-guard/src/main.js:
row.activityCount >= 10
Actions NOT Rate Limited:
like- Allows unlimited likes/unlikesview- Allows unlimited view tracking
Comments Guard (60 requests/minute)
Fromfunctions/comments-guard/src/main.js:60:
- Comments are shorter, faster to create
- Live discussions require higher throughput
- Less resource-intensive than posts with images
Rooms Guard (10 requests/minute)
Fromfunctions/rooms-guard/src/main.js:73:
- Rooms are high-value resources
- Creation requires more validation
- Lower limit prevents spam room creation
Room Messages Guard (60 requests/minute)
Fromfunctions/room-message-guard/src/main.js:76:
- Real-time chat requires fast message delivery
- Users need to send multiple messages quickly during live matches
- Similar to comments in usage pattern
Handling Rate Limit Errors
Client-Side Detection
Rate limit errors are thrown as exceptions:Error Message Patterns
| Pattern | Meaning | User Action |
|---|---|---|
Rate limit exceeded: Too many requests in a short period | Generic rate limit | Wait 60 seconds |
Rate limit exceeded: Too many requests. Please try again later. | Comments/messages | Wait 60 seconds |
Retry Strategy
Configuring Rate Limits
Modifying Limits
To change rate limits, edit the guard function’srateLimitCheck function:
Example: Increase post creation limit to 20/minute
Deployment
After modifying rate limits:- Test the function locally if possible
- Deploy the updated function:
- Monitor logs for the first few minutes
- Update this documentation
Different Limits per Action
Some functions use action-specific limits:Window Expiration
Rate limit records automatically become irrelevant after their time window passes: Old Window Example:- Current time:
2024-01-15 10:31:30(windowKey:28953451) - Existing record:
windowKey: 28953450(10:30:00 - 10:30:59) - Query won’t match old windowKey, so new record is created
Cleanup Strategy
Old records can be cleaned up with a scheduled function:Atomic Operations
Rate limiting usesincrementRowColumn for atomic counter updates:
- Prevents race conditions when multiple requests arrive simultaneously
- Ensures accurate counting even under high concurrency
- No need for database locks or transactions
Best Practices
1. Check Before Operations
Always check rate limits BEFORE expensive operations:2. Use Descriptive Activity Names
Make activity identifiers clear and consistent: ✅ Good:3. Set Appropriate Limits
Consider the resource cost and user experience:| Resource Cost | Recommended Limit | Example |
|---|---|---|
| High (images, complex validation) | 5-10/min | Post creation |
| Medium (database writes) | 10-20/min | Room updates |
| Low (simple text, reads) | 30-60/min | Comments, messages |
4. Provide Clear Error Messages
Include context in rate limit errors:5. Monitor Rate Limit Hits
Log when users hit limits for analytics:Bypassing Rate Limits
Admin Exceptions
To allow admins to bypass rate limits:Per-User Custom Limits
Implement tiered limits based on user status:Troubleshooting
Users Reporting False Rate Limits
Check:- User’s device clock accuracy (affects window calculation)
- Multiple devices with same account (counters are shared)
- Browser/app caching old error messages
Cleanup Not Working
Old records accumulating: Solution: Manually delete old records via Appwrite Console or create a maintenance function:Rate Limits Too Restrictive
Symptoms:- High rate limit error frequency in logs
- User complaints about “can’t post” errors
- Legitimate usage being blocked
- Increase the limit in the guard function
- Implement burst allowance (allow 15 in first 10 seconds, then 10/min)
- Add user feedback showing cooldown timer
Related Documentation
- Guard Functions - Overview of all guard functions
- Database Schema - Complete database structure
- Architecture - Technical architecture and implementation details