Skip to content

Commit 9549cec

Browse files
committed
Add: CheckSpamPostJob to cronPlugin
1 parent c3e7edc commit 9549cec

File tree

6 files changed

+84
-29
lines changed

6 files changed

+84
-29
lines changed

packages/velog-cron/src/common/plugins/globals/cronPlugin.ts

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { DeleteFeedJob } from '@jobs/DeleteFeedJob.js'
66
import { FastifyPluginCallback } from 'fastify'
77
import { container } from 'tsyringe'
88
import { ENV } from '@env'
9+
import { CheckSpamPostJob } from '@jobs/CheckSpamPostJob.js'
910

1011
const cronPlugin: FastifyPluginCallback = async (fastfiy, opts, done) => {
1112
const calculatePostScoreJob = container.resolve(CalculatePostScoreJob)
@@ -15,6 +16,7 @@ const cronPlugin: FastifyPluginCallback = async (fastfiy, opts, done) => {
1516
const statsDailyJob = container.resolve(StatsDaily)
1617
const statsWeeklyJob = container.resolve(StatsWeekly)
1718
const statsMonthlyJob = container.resolve(StatsMonthly)
19+
const checkSpamPostJob = container.resolve(CheckSpamPostJob)
1820

1921
// 덜 실행하면서, 실행되는 순서로 정렬
2022
// crontime은 UTC 기준으로 작성되기 때문에 KST에서 9시간을 빼줘야함
@@ -46,6 +48,11 @@ const cronPlugin: FastifyPluginCallback = async (fastfiy, opts, done) => {
4648
jobService: calculatePostScoreJob,
4749
param: 0.5,
4850
},
51+
{
52+
name: 'check post spam in every 2 minutes',
53+
cronTime: '*/2 * * * *', // every 2 minutes
54+
jobService: checkSpamPostJob,
55+
},
4956
// Stats Start
5057
{
5158
name: 'providing a count of new users and posts from the past 1 day',
@@ -79,6 +86,13 @@ const cronPlugin: FastifyPluginCallback = async (fastfiy, opts, done) => {
7986
if (ENV.appEnv !== 'production') {
8087
const immediateRunJobs = jobDescription.filter((job) => !!job.isImmediateExecute)
8188
await Promise.all(immediateRunJobs.map(createTick))
89+
const crons = immediateRunJobs.map(createJob)
90+
await Promise.all(
91+
crons.map((cron) => {
92+
console.log(`${cron.name} is registered`)
93+
cron.start()
94+
}),
95+
)
8296
}
8397

8498
if (ENV.dockerEnv === 'production') {
@@ -93,7 +107,6 @@ const cronPlugin: FastifyPluginCallback = async (fastfiy, opts, done) => {
93107
} catch (error) {
94108
console.error('Error initializing cron jobs:', error)
95109
} finally {
96-
console.log('finally')
97110
done()
98111
}
99112
}
@@ -105,14 +118,7 @@ function isNeedParamJobService(arg: any): arg is NeedParamJobService {
105118
}
106119

107120
function isNotNeedParamJobService(arg: any): arg is NotNeedParamJobService {
108-
return (
109-
arg.jobService instanceof GenerateFeedJob ||
110-
arg.jobService instanceof GenerateTrendingWritersJob ||
111-
arg.jobService instanceof DeleteFeedJob ||
112-
arg.jobService instanceof StatsDaily ||
113-
arg.jobService instanceof StatsWeekly ||
114-
arg.jobService instanceof StatsMonthly
115-
)
121+
return arg.jobService instanceof CalculatePostScoreJob === false
116122
}
117123

118124
async function createTick(description: JobDescription) {
@@ -134,24 +140,27 @@ async function createTick(description: JobDescription) {
134140

135141
type JobDescription = NeedParamJobService | NotNeedParamJobService
136142

137-
type NeedParamJobService = {
143+
type JobService =
144+
| CalculatePostScoreJob
145+
| GenerateFeedJob
146+
| GenerateTrendingWritersJob
147+
| DeleteFeedJob
148+
| StatsDaily
149+
| StatsWeekly
150+
| StatsMonthly
151+
| CheckSpamPostJob
152+
153+
type BaseJobService = {
138154
name: string
139155
cronTime: string
140-
param: any
141156
isImmediateExecute?: boolean
157+
}
158+
159+
type NeedParamJobService = BaseJobService & {
160+
param: any
142161
jobService: CalculatePostScoreJob
143162
}
144163

145-
type NotNeedParamJobService = {
146-
name: string
147-
cronTime: string
148-
param?: undefined
149-
isImmediateExecute?: boolean
150-
jobService:
151-
| GenerateFeedJob
152-
| GenerateTrendingWritersJob
153-
| DeleteFeedJob
154-
| StatsDaily
155-
| StatsWeekly
156-
| StatsMonthly
164+
type NotNeedParamJobService = Omit<BaseJobService, 'param'> & {
165+
jobService: Exclude<JobService, CalculatePostScoreJob>
157166
}

packages/velog-cron/src/env.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const env = z.object({
4242
discordBotToken: z.string(),
4343
discordStatsChannel: z.string(),
4444
discordSpamChannel: z.string(),
45+
discordErrorChannel: z.string(),
4546
})
4647

4748
export const ENV = env.parse({
@@ -54,4 +55,5 @@ export const ENV = env.parse({
5455
discordBotToken: process.env.DISCORD_BOT_TOKEN,
5556
discordStatsChannel: process.env.DISCORD_STATS_CHANNEL,
5657
discordSpamChannel: process.env.DISCORD_SPAM_CHANNEL,
58+
discordErrorChannel: process.env.DISCORD_ERROR_CHANNEL,
5759
})
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { injectable, singleton } from 'tsyringe'
2+
import { Job, JobProgress } from './JobProgress.js'
3+
import { PostService } from '@services/PostService/index.js'
4+
import { CheckPostSpamArgs, RedisService } from '@lib/redis/RedisService.js'
5+
import { DiscordService } from '@lib/discord/DiscordService.js'
6+
7+
@injectable()
8+
@singleton()
9+
export class CheckSpamPostJob extends JobProgress implements Job {
10+
constructor(
11+
private readonly redis: RedisService,
12+
private readonly discord: DiscordService,
13+
private readonly postService: PostService,
14+
) {
15+
super()
16+
}
17+
public async runner(): Promise<void> {
18+
console.log('PostSpamCheckJob start...')
19+
console.time('PostSpamCheckJob')
20+
21+
const spamQueueName = this.redis.queueName.checkPostSpam
22+
let handledQueueCount = 0
23+
while (true) {
24+
const item = await this.redis.lindex(spamQueueName, 0)
25+
if (!item) break
26+
const data: CheckPostSpamArgs = JSON.parse(item)
27+
try {
28+
await this.postService.checkSpam(data)
29+
} catch (error) {
30+
const message = { message: 'PostSpamCheckJob error', payload: item, error: error }
31+
this.discord.sendMessage('error', JSON.stringify(message))
32+
} finally {
33+
await this.redis.lpop(spamQueueName)
34+
handledQueueCount++
35+
}
36+
}
37+
38+
console.log(`handled Queue count: ${handledQueueCount}`)
39+
console.timeEnd('PostSpamCheckJob')
40+
}
41+
}

packages/velog-cron/src/lib/discord/DiscordService.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export class DiscordService {
2525
public async sendMessage(type: MessageType, message: string) {
2626
this.isSending = true
2727

28-
const frequentWord = ['connection pool', 'canceling statement', 'Not allow origin']
28+
const frequentWord: string[] = []
2929
const isFrequentWordIncluded = frequentWord.some((word) => message.includes(word))
3030

3131
if (isFrequentWordIncluded) {
@@ -44,6 +44,7 @@ export class DiscordService {
4444
const channelMapper: Record<MessageType, string> = {
4545
stats: ENV.discordStatsChannel,
4646
spam: ENV.discordSpamChannel,
47+
error: ENV.discordErrorChannel,
4748
}
4849

4950
const channelId = channelMapper[type]
@@ -71,4 +72,4 @@ export class DiscordService {
7172
}
7273
}
7374

74-
type MessageType = 'stats' | 'spam'
75+
type MessageType = 'stats' | 'spam' | 'error'

packages/velog-cron/src/services/PostService/index.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { DbService } from '@lib/db/DbService.js'
2-
import { CheckPostSpamArgs } from '@lib/redis/RedisService'
2+
import { CheckPostSpamArgs } from '@lib/redis/RedisService.js'
33
import { Post, Prisma } from '@prisma/client'
44
import { injectable, singleton } from 'tsyringe'
55
import geoip from 'geoip-country'
66
import { subMonths } from 'date-fns'
7-
import { DiscordService } from '@lib/discord/DiscordService'
7+
import { DiscordService } from '@lib/discord/DiscordService.js'
8+
import { NotFoundError } from '@errors/NotfoundError.js'
89

910
interface Service {
1011
findById(postId: string): Promise<Post | null>
@@ -86,7 +87,7 @@ export class PostService implements Service {
8687
})
8788

8889
if (!post) {
89-
throw new Error('Not found Post')
90+
throw new NotFoundError('Not found Post')
9091
}
9192

9293
const user = await this.db.user.findUnique({
@@ -99,7 +100,7 @@ export class PostService implements Service {
99100
})
100101

101102
if (!user) {
102-
throw new Error('Not found User')
103+
throw new NotFoundError('Not found User')
103104
}
104105

105106
const country = geoip.lookup(ip)?.country ?? ''

packages/velog-server/src/services/PostApiService/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ export class PostApiService implements Service {
289289
// check spam
290290
setTimeout(() => {
291291
if (isSpam) return
292+
if (isTusted) return
292293
const queueData: CheckPostSpamArgs = {
293294
post_id: post.id,
294295
user_id: signedUserId,

0 commit comments

Comments
 (0)