From 08c4624fceb856cfa12c2836f38f2eb39384b75f Mon Sep 17 00:00:00 2001 From: Hongbo Wu Date: Thu, 4 Jan 2024 18:03:34 +0800 Subject: [PATCH] save the url in redis for 8 hours so rss-feeder will not try to re-save it --- packages/api/package.json | 1 + packages/api/src/redis.ts | 18 ++++++++++++++++++ packages/api/src/server.ts | 3 +++ packages/api/src/services/save_page.ts | 9 +++++++++ packages/api/src/util.ts | 11 +++++++++++ packages/rss-handler/src/index.ts | 2 +- 6 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 packages/api/src/redis.ts diff --git a/packages/api/package.json b/packages/api/package.json index 34d9b24fb..75cecca83 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -82,6 +82,7 @@ "pg": "^8.3.3", "postgrator": "^4.2.0", "private-ip": "^2.3.3", + "redis": "^4.3.1", "rss-parser": "^3.13.0", "sanitize-html": "^2.3.2", "sax": "^1.3.0", diff --git a/packages/api/src/redis.ts b/packages/api/src/redis.ts new file mode 100644 index 000000000..14559c0be --- /dev/null +++ b/packages/api/src/redis.ts @@ -0,0 +1,18 @@ +import { createClient } from 'redis' +import { env } from './env' + +export const redisClient = createClient({ + url: env.redis.url, + socket: { + tls: env.redis.url?.startsWith('rediss://'), // rediss:// is the protocol for TLS + cert: env.redis.cert?.replace(/\\n/g, '\n'), // replace \n with new line + rejectUnauthorized: false, // for self-signed certs + connectTimeout: 10000, // 10 seconds + reconnectStrategy(retries: number): number | Error { + if (retries > 10) { + return new Error('Retries exhausted') + } + return 1000 + }, + }, +}) diff --git a/packages/api/src/server.ts b/packages/api/src/server.ts index 1bb75a085..2380e3c37 100755 --- a/packages/api/src/server.ts +++ b/packages/api/src/server.ts @@ -15,6 +15,7 @@ import { config, loggers } from 'winston' import { makeApolloServer } from './apollo' import { appDataSource } from './data_source' import { env } from './env' +import { redisClient } from './redis' import { articleRouter } from './routers/article_router' import { authRouter } from './routers/auth/auth_router' import { mobileAuthRouter } from './routers/auth/mobile/mobile_auth_router' @@ -157,6 +158,8 @@ const main = async (): Promise => { // as healthy. await appDataSource.initialize() + await redisClient.connect() + const { app, apollo, httpServer } = createApp() await apollo.start() diff --git a/packages/api/src/services/save_page.ts b/packages/api/src/services/save_page.ts index 442dcea93..a49f9ac86 100644 --- a/packages/api/src/services/save_page.ts +++ b/packages/api/src/services/save_page.ts @@ -13,6 +13,7 @@ import { SavePageInput, SaveResult, } from '../generated/graphql' +import { redisClient } from '../redis' import { authTrx } from '../repository' import { enqueueThumbnailTask } from '../utils/createTask' import { @@ -194,6 +195,14 @@ export const savePage = async ( } } + // save the url in redis for 8 hours so rss-feeder won't try to re-save it + const redisKey = `recent-saved-item:${user.id}:${itemToSave.originalUrl}` + const expireInSeconds = 60 * 60 * 8 + await redisClient.set(redisKey, 1, { + EX: expireInSeconds, + NX: true, + }) + return { clientRequestId, url: `${homePageURL()}/${user.profile.username}/${slug}`, diff --git a/packages/api/src/util.ts b/packages/api/src/util.ts index c056d17cd..f37b51587 100755 --- a/packages/api/src/util.ts +++ b/packages/api/src/util.ts @@ -109,6 +109,10 @@ interface BackendEnv { max: number } } + redis: { + url?: string + cert?: string + } } /*** @@ -173,6 +177,8 @@ const nullableEnvVars = [ 'INTEGRATION_EXPORTER_URL', 'INTEGRATION_IMPORTER_URL', 'SUBSCRIPTION_FEED_MAX', + 'REDIS_URL', + 'REDIS_CERT', ] // Allow some vars to be null/empty /* If not in GAE and Prod/QA/Demo env (f.e. on localhost/dev env), allow following env vars to be null */ @@ -316,6 +322,10 @@ export function getEnv(): BackendEnv { : 256, // default to 256 }, } + const redis = { + url: parse('REDIS_URL'), + cert: parse('REDIS_CERT'), + } return { pg, @@ -338,6 +348,7 @@ export function getEnv(): BackendEnv { gcp, pocket, subscription, + redis, } } diff --git a/packages/rss-handler/src/index.ts b/packages/rss-handler/src/index.ts index 2da93f3f7..4604690ef 100644 --- a/packages/rss-handler/src/index.ts +++ b/packages/rss-handler/src/index.ts @@ -224,7 +224,7 @@ const isItemRecentlySaved = async ( userId: string, url: string ) => { - const key = `rss-recent-save:${userId}:${url}` + const key = `recent-saved-item:${userId}:${url}` const result = await redisClient.get(key) return !!result }