Skip to content

Commit f46d757

Browse files
committed
feat: 重复创建工单保护
1 parent f21dc1f commit f46d757

File tree

1 file changed

+41
-0
lines changed

1 file changed

+41
-0
lines changed

api/ticket/api.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const AV = require('leanengine')
33
const { Router } = require('express')
44
const { check, query } = require('express-validator')
55
const Redis = require('ioredis')
6+
const crypto = require('crypto')
67

78
const { captureException } = require('../errorHandler')
89
const { checkPermission } = require('../../oauth/lc')
@@ -127,6 +128,7 @@ router.post(
127128
}
128129
// === Rate Limiting End ===
129130

131+
// === Duplicate Check Start ===
130132
const {
131133
title,
132134
category_id,
@@ -138,6 +140,28 @@ router.post(
138140
} = req.body
139141
const author = req.user
140142

143+
if (redisClient) {
144+
try {
145+
const titleHash = crypto.createHash('sha1').update(title).digest('hex')
146+
const duplicateCheckKey = `duplicate_check:ticket:${author.id}:${titleHash}`
147+
const existingTicketId = await redisClient.get(duplicateCheckKey)
148+
149+
if (existingTicketId) {
150+
console.log(
151+
`Duplicate ticket creation detected for user ${author.id} with title hash ${titleHash}. Returning existing ticket ID: ${existingTicketId}`
152+
)
153+
return res.json({ id: existingTicketId })
154+
}
155+
} catch (error) {
156+
console.error(`Redis duplicate check failed for user ${author.id}:`, error)
157+
captureException(error, {
158+
extra: { component: 'TicketAPI', msg: 'Duplicate check failed', userId: author.id },
159+
})
160+
// Fail open: If Redis fails, allow creation.
161+
}
162+
}
163+
// === Duplicate Check End ===
164+
141165
const ticket = await Ticket.create({
142166
title,
143167
category_id,
@@ -151,6 +175,23 @@ router.post(
151175
await ticket.saveFormValues(form_values)
152176
}
153177

178+
// === Store in Redis After Creation ===
179+
if (redisClient) {
180+
try {
181+
const titleHash = crypto.createHash('sha1').update(title).digest('hex')
182+
const duplicateCheckKey = `duplicate_check:ticket:${author.id}:${titleHash}`
183+
// Set the key with the new ticket ID and 2-minute expiry
184+
await redisClient.set(duplicateCheckKey, ticket.id, 'EX', 120)
185+
} catch (error) {
186+
console.error(`Redis set after creation failed for ticket ${ticket.id}:`, error)
187+
captureException(error, {
188+
extra: { component: 'TicketAPI', msg: 'Set duplicate key failed', ticketId: ticket.id },
189+
})
190+
// Log error but don't block response
191+
}
192+
}
193+
// === Store in Redis End ===
194+
154195
res.json({ id: ticket.id })
155196
})
156197
)

0 commit comments

Comments
 (0)