rate limit save url action in redis: max 5 save urls in a minute

This commit is contained in:
Hongbo Wu
2024-07-25 13:08:38 +08:00
parent c503b47ea2
commit 156feb8e17

View File

@ -8,10 +8,11 @@ import {
PageType,
} from '../generated/graphql'
import { createPubSubClient, PubsubClient } from '../pubsub'
import { redisDataSource } from '../redis_data_source'
import { enqueueParseRequest } from '../utils/createTask'
import { cleanUrl, generateSlug } from '../utils/helpers'
import { logger } from '../utils/logger'
import { countByCreatedAt, createOrUpdateLibraryItem } from './library_item'
import { createOrUpdateLibraryItem } from './library_item'
interface PageSaveRequest {
user: User
@ -33,19 +34,47 @@ const SAVING_CONTENT = 'Your link is being saved...'
const isPrivateIP = privateIpLib.default
const recentSavedItemKey = (userId: string) => `recent-saved-item:${userId}`
const addRecentSavedItem = async (userId: string) => {
const redisClient = redisDataSource.redisClient
if (redisClient) {
const key = recentSavedItemKey(userId)
try {
// add now to the sorted set for rate limiting
await redisClient.zadd(key, Date.now(), Date.now())
} catch (error) {
logger.error('error adding recently saved item in redis', {
key,
error,
})
}
}
}
// 5 items saved in the last minute: use low queue
// default: use normal queue
const getPriorityByRateLimit = async (
userId: string
): Promise<'low' | 'high'> => {
const now = new Date()
const count = await countByCreatedAt(
userId,
new Date(now.getTime() - 60 * 1000), // 1 minute ago
now
)
): Promise<'low' | 'high' | undefined> => {
const redisClient = redisDataSource.redisClient
if (redisClient) {
const oneMinuteAgo = Date.now() - 60 * 1000
const key = recentSavedItemKey(userId)
return count >= 5 ? 'low' : 'high'
try {
// Remove items older than one minute
await redisClient.zremrangebyscore(key, '-inf', oneMinuteAgo)
// Count items in the last minute
const count = await redisClient.zcard(key)
return count >= 5 ? 'low' : 'high'
} catch (error) {
logger.error('Failed to get priority by rate limit', { userId, error })
}
}
}
export const validateUrl = (url: string): URL => {
@ -123,8 +152,12 @@ export const createPageSaveRequest = async ({
pubsub
)
// add to recent saved item
await addRecentSavedItem(userId)
// get priority by checking rate limit if not specified
priority = priority || (await getPriorityByRateLimit(userId))
logger.debug('priority', { priority })
// enqueue task to parse item
await enqueueParseRequest({