Skip to content

Commit

Permalink
fix(be): update redis test key for race condition (#2190)
Browse files Browse the repository at this point in the history
* fix(be): change testKey for race condition

* fix(be): update cache set and get logic

* fix(be): update handleRunMessage to apply changed cache

* fix(be): ensure consistency with repo

* fix(be): print output when compile error
  • Loading branch information
donghun1214 authored Nov 8, 2024
1 parent 560a496 commit 73b897f
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 41 deletions.
44 changes: 26 additions & 18 deletions apps/backend/apps/client/src/submission/submission-sub.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { Cache } from 'cache-manager'
import { plainToInstance } from 'class-transformer'
import { validateOrReject, ValidationError } from 'class-validator'
import { Span } from 'nestjs-otel'
import { testKey } from '@libs/cache'
import { testKey, userTestcasesKey } from '@libs/cache'
import {
CONSUME_CHANNEL,
EXCHANGE,
Expand Down Expand Up @@ -76,28 +76,36 @@ export class SubmissionSubscriptionService implements OnModuleInit {
}

async handleRunMessage(msg: JudgerResponse, userId: number): Promise<void> {
const key = testKey(userId)
const status = Status(msg.resultCode)
const testcaseId = msg.judgeResult?.testcaseId
const output = this.parseError(msg, status)

const testcases =
(await this.cacheManager.get<
{
id: number
result: ResultStatus
output?: string
}[]
>(key)) ?? []

testcases.forEach((tc) => {
if (!testcaseId || tc.id === testcaseId) {
tc.result = status
tc.output = output
if (!testcaseId) {
const key = userTestcasesKey(userId)
const testcaseIds = (await this.cacheManager.get<number[]>(key)) ?? []

for (const testcaseId of testcaseIds) {
await this.cacheManager.set(
testKey(userId, testcaseId),
{ id: testcaseId, result: status, output },
TEST_SUBMISSION_EXPIRE_TIME
)
}
})
return
}

const key = testKey(userId, testcaseId)
const testcase = await this.cacheManager.get<{
id: number
result: ResultStatus
output?: string
}>(key)
if (testcase) {
testcase.id = testcaseId
testcase.result = status
testcase.output = output
}

await this.cacheManager.set(key, testcases, TEST_SUBMISSION_EXPIRE_TIME)
await this.cacheManager.set(key, testcase, TEST_SUBMISSION_EXPIRE_TIME)
}

parseError(msg: JudgerResponse, status: ResultStatus): string {
Expand Down
46 changes: 24 additions & 22 deletions apps/backend/apps/client/src/submission/submission.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { AxiosRequestConfig } from 'axios'
import { Cache } from 'cache-manager'
import { plainToInstance } from 'class-transformer'
import { Span } from 'nestjs-otel'
import { testKey } from '@libs/cache'
import { testKey, userTestcasesKey } from '@libs/cache'
import {
MIN_DATE,
OPEN_SPACE_ID,
Expand Down Expand Up @@ -375,23 +375,16 @@ export class SubmissionService {
}
})

const testcases: {
id: number
result: ResultStatus
}[] = []

for (const testcase of rawTestcases) {
testcases.push({
id: testcase.id,
result: 'Judging'
})
const testcaseIds: number[] = []
for (const rawTestcase of rawTestcases) {
await this.cacheManager.set(
testKey(userId, rawTestcase.id),
{ id: rawTestcase.id, result: 'Judging' },
TEST_SUBMISSION_EXPIRE_TIME
)
testcaseIds.push(rawTestcase.id)
}

await this.cacheManager.set(
testKey(userId),
testcases,
TEST_SUBMISSION_EXPIRE_TIME
)
await this.cacheManager.set(userTestcasesKey(userId), testcaseIds)

await this.publish.publishJudgeRequestMessage(
submissionDto.code,
Expand All @@ -401,14 +394,23 @@ export class SubmissionService {
}

async getTestResult(userId: number) {
const key = testKey(userId)
return await this.cacheManager.get<
{
const testCasesKey = userTestcasesKey(userId)
const testcases =
(await this.cacheManager.get<number[]>(testCasesKey)) ?? []

const results: { id: number; result: ResultStatus; output?: string }[] = []
for (const testcaseId of testcases) {
const key = testKey(userId, testcaseId)
const testcase = await this.cacheManager.get<{
id: number
result: ResultStatus
output?: string
}[]
>(key)
}>(key)
if (testcase) {
results.push(testcase)
}
}
return results
}

@Span()
Expand Down
4 changes: 3 additions & 1 deletion apps/backend/libs/cache/src/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ export const joinGroupCacheKey = (groupId: number) => `group:${groupId}`
export const invitationCodeKey = (code: string) => `invite:${code}`
export const invitationGroupKey = (groupId: number) => `invite:to:${groupId}`

export const testKey = (userId: number) => `test:user:${userId}`
export const testKey = (userId: number, testcaseId: number) =>
`test:user:${userId}:testcase:${testcaseId}`
export const userTestcasesKey = (userId: number) => `test:user:${userId}`

0 comments on commit 73b897f

Please sign in to comment.