Skip to content

Commit b413fbb

Browse files
committed
🚑 poll funfacts worker do not loop over simulations every time
1 parent ede5bc0 commit b413fbb

File tree

8 files changed

+89
-22
lines changed

8 files changed

+89
-22
lines changed

scripts/NGC-1784-20250331.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const main = async () => {
1717
let updatedPolls = 0
1818

1919
for await (const poll of batchPolls) {
20-
await updatePollFunFacts(poll.id, { session: prisma })
20+
await updatePollFunFacts({ pollId: poll.id }, { session: prisma })
2121

2222
updatedPolls++
2323

src/adapters/redis/constant.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export const CHANNELS = {
33
}
44

55
export const KEYS = {
6+
pollsFunFactsResults: 'pollsFunFactsResults',
67
geolocationSortedIps: 'geolocationSortedIps',
78
geolocationCountries: 'geolocationCountries',
89
}

src/features/organisations/organisations.service.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -430,19 +430,26 @@ export const fetchPublicPoll = async ({
430430
}
431431

432432
export const updatePollFunFacts = async (
433-
pollId: string,
433+
{ pollId, simulationId }: { pollId: string; simulationId?: string },
434434
{ session }: { session?: Session } = {}
435435
) => {
436436
return transaction(async (session) => {
437-
const funFacts = await getPollFunFacts({ id: pollId }, { session })
437+
const funFacts = await getPollFunFacts(
438+
{ id: pollId, simulationId },
439+
{ session }
440+
)
438441

439442
await setPollFunFacts(pollId, funFacts, { session })
440443
}, session)
441444
}
442445

443-
export const updatePollFunFactsAfterSimulationChange = (
446+
export const updatePollFunFactsAfterSimulationChange = ({
447+
simulationId,
448+
created,
449+
}: {
444450
simulationId: string
445-
) => {
451+
created: boolean
452+
}) => {
446453
return transaction(async (session) => {
447454
const simulationPoll = await findSimulationPoll(
448455
{ simulationId },
@@ -455,6 +462,9 @@ export const updatePollFunFactsAfterSimulationChange = (
455462

456463
const { pollId } = simulationPoll
457464

458-
return updatePollFunFacts(pollId, { session })
465+
return updatePollFunFacts(
466+
{ pollId, ...(created ? { simulationId } : {}) },
467+
{ session }
468+
)
459469
}, prisma)
460470
}

src/features/simulations/__tests__/create-poll-simulation.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ describe('Given a NGC user', () => {
3333
const { computedResults, nom, situation } = getRandomTestCase()
3434

3535
afterEach(async () => {
36+
await EventBus.flush()
3637
await Promise.all([
3738
prisma.organisationAdministrator.deleteMany(),
3839
prisma.simulationPoll.deleteMany(),

src/features/simulations/handlers/compute-poll-fun-facts.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import type { SimulationUpsertedAsyncEvent } from '../events/SimulationUpserted.
55
export const computePollFunFacts: Handler<SimulationUpsertedAsyncEvent> = ({
66
attributes: {
77
simulation: { id },
8+
created,
89
},
910
}) => {
10-
return updatePollFunFactsAfterSimulationChange(id)
11+
return updatePollFunFactsAfterSimulationChange({ simulationId: id, created })
1112
}

src/features/simulations/simulations.repository.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import type { UserParams } from '../users/users.validator'
1515
import type {
1616
SimulationCreateDto,
1717
SimulationParticipantCreateDto,
18-
UserSimulationParams,
1918
} from './simulations.validator'
2019

2120
export const createUserSimulation = async (
@@ -151,17 +150,13 @@ export const fetchUserSimulations = (
151150
})
152151
}
153152

154-
export const fetchUserSimulation = (
155-
{
156-
simulationId,
157-
// userId,
158-
}: UserSimulationParams,
153+
export const fetchSimulationById = (
154+
{ simulationId }: { simulationId: string },
159155
{ session }: { session: Session }
160156
) => {
161157
return session.simulation.findUniqueOrThrow({
162158
where: {
163159
id: simulationId,
164-
// userId,
165160
},
166161
select: defaultSimulationSelection,
167162
})

src/features/simulations/simulations.service.ts

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import type Engine from 'publicodes'
1111
import { prisma } from '../../adapters/prisma/client'
1212
import type { Session } from '../../adapters/prisma/transaction'
1313
import { transaction } from '../../adapters/prisma/transaction'
14+
import { redis } from '../../adapters/redis/client'
15+
import { KEYS } from '../../adapters/redis/constant'
1416
import { EntityNotFoundException } from '../../core/errors/EntityNotFoundException'
1517
import { ForbiddenException } from '../../core/errors/ForbiddenException'
1618
import { EventBus } from '../../core/event-bus/event-bus'
@@ -26,7 +28,7 @@ import {
2628
createPollUserSimulation,
2729
createUserSimulation,
2830
fetchPollSimulations,
29-
fetchUserSimulation,
31+
fetchSimulationById,
3032
fetchUserSimulations,
3133
} from './simulations.repository'
3234
import type {
@@ -48,7 +50,7 @@ const simulationToDto = (
4850
polls,
4951
user,
5052
...rest
51-
}: Partial<Awaited<ReturnType<typeof fetchUserSimulation>>>,
53+
}: Partial<Awaited<ReturnType<typeof fetchSimulationById>>>,
5254
connectedUser: string
5355
) => ({
5456
...rest,
@@ -105,7 +107,7 @@ export const fetchSimulations = async (params: UserParams) => {
105107
export const fetchSimulation = async (params: UserSimulationParams) => {
106108
try {
107109
const simulation = await transaction(
108-
(session) => fetchUserSimulation(params, { session }),
110+
(session) => fetchSimulationById(params, { session }),
109111
prisma
110112
)
111113

@@ -237,7 +239,7 @@ const isValidSimulation = <T>(
237239
].every((v) => v <= MAX_VALUE)
238240
}
239241

240-
const getFunFactValues = async (
242+
const computeAllFunFactValues = async (
241243
{ id, engine }: { id: string; engine?: Engine },
242244
{ session }: { session: Session }
243245
) => {
@@ -271,14 +273,70 @@ const getFunFactValues = async (
271273
}, funFactValues)
272274
}
273275

274-
return {
275-
simulationCount,
276-
funFactValues,
276+
return { simulationCount, funFactValues }
277+
}
278+
279+
const getFunFactValues = async (
280+
{
281+
id,
282+
simulationId,
283+
engine,
284+
}: { id: string; simulationId?: string; engine?: Engine },
285+
{ session }: { session: Session }
286+
) => {
287+
const redisKey = `${KEYS.pollsFunFactsResults}:${id}`
288+
289+
let result:
290+
| {
291+
simulationCount: number
292+
funFactValues: { [key in DottedName]?: number }
293+
}
294+
| undefined
295+
if (simulationId) {
296+
const rawPreviousFunFactValues = await redis.get(redisKey)
297+
if (rawPreviousFunFactValues) {
298+
const result = JSON.parse(rawPreviousFunFactValues)
299+
const simulation = await fetchSimulationById(
300+
{ simulationId },
301+
{ session }
302+
)
303+
304+
if (isValidSimulation(simulation)) {
305+
const { situation } = simulation
306+
Object.values(funFactsRules).reduce((acc, dottedName) => {
307+
if (dottedName in frRules) {
308+
acc[dottedName] =
309+
(acc[dottedName] || 0) +
310+
(engine
311+
? getSituationDottedNameValueWithEngine({
312+
dottedName,
313+
situation,
314+
engine,
315+
})
316+
: getSituationDottedNameValue({
317+
dottedName,
318+
situation,
319+
rules: frRules,
320+
}))
321+
}
322+
return acc
323+
}, result.funFactValues)
324+
}
325+
}
326+
}
327+
328+
if (!result) {
329+
result = await computeAllFunFactValues({ id, engine }, { session })
277330
}
331+
332+
await redis.set(redisKey, JSON.stringify(result))
333+
await redis.expire(redisKey, 60 * 60)
334+
335+
return result
278336
}
279337

280338
export const getPollFunFacts = async (
281-
params: { id: string; engine?: Engine },
339+
params: { id: string; simulationId?: string; engine?: Engine },
282340
session: { session: Session }
283341
) => {
284342
const { funFactValues, simulationCount } = await getFunFactValues(

src/worker.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ redis.on('message', async (_, message) => {
3030
await EventBus.once(event)
3131
logger.info('Handled event', { event })
3232
} catch (err) {
33+
console.error(err.reasons[0].errors[0].error)
3334
logger.error('Redis api event failure', err)
3435
}
3536
})

0 commit comments

Comments
 (0)