diff options
| author | nsfisis <nsfisis@gmail.com> | 2024-08-08 19:30:20 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2024-08-08 19:30:20 +0900 |
| commit | 9e5500269746d3826382a6dec78f0e82cfda0d42 (patch) | |
| tree | d8f15d4081132d6cfff3ea3b02f197b2d6bad700 /backend/taskqueue/processor.go | |
| parent | 401a28944fc0408811aedadd1c3104e2e2d4d7fe (diff) | |
| parent | 113c83b19acc58fbd46e8acdac67ff1a112d0d8c (diff) | |
| download | phperkaigi-2025-albatross-9e5500269746d3826382a6dec78f0e82cfda0d42.tar.gz phperkaigi-2025-albatross-9e5500269746d3826382a6dec78f0e82cfda0d42.tar.zst phperkaigi-2025-albatross-9e5500269746d3826382a6dec78f0e82cfda0d42.zip | |
Merge branch 'feat/taskqueue'
Diffstat (limited to 'backend/taskqueue/processor.go')
| -rw-r--r-- | backend/taskqueue/processor.go | 289 |
1 files changed, 122 insertions, 167 deletions
diff --git a/backend/taskqueue/processor.go b/backend/taskqueue/processor.go index 1d4c412..b64b01c 100644 --- a/backend/taskqueue/processor.go +++ b/backend/taskqueue/processor.go @@ -6,195 +6,150 @@ import ( "encoding/json" "fmt" "net/http" - "strings" - - "github.com/hibiken/asynq" "github.com/nsfisis/iosdc-japan-2024-albatross/backend/db" ) -type ExecProcessor struct { +type processor struct { q *db.Queries - c chan string } -func NewExecProcessor(q *db.Queries, c chan string) *ExecProcessor { - return &ExecProcessor{ +func newProcessor(q *db.Queries) processor { + return processor{ q: q, - c: c, } } -func (p *ExecProcessor) ProcessTask(ctx context.Context, t *asynq.Task) error { - var payload TaskExecPlayload - if err := json.Unmarshal(t.Payload(), &payload); err != nil { - return fmt.Errorf("json.Unmarshal failed: %v: %w", err, asynq.SkipRetry) - } - +func (p *processor) doProcessTaskCreateSubmissionRecord( + ctx context.Context, + payload *TaskPayloadCreateSubmissionRecord, +) (*TaskResultCreateSubmissionRecord, error) { // TODO: upsert - // Create submission record. submissionID, err := p.q.CreateSubmission(ctx, db.CreateSubmissionParams{ - GameID: int32(payload.GameID), - UserID: int32(payload.UserID), - Code: payload.Code, - CodeSize: int32(len(payload.Code)), // TODO: exclude whitespaces. + GameID: int32(payload.GameID()), + UserID: int32(payload.UserID()), + Code: payload.Code(), + CodeSize: int32(payload.CodeSize), }) if err != nil { - return fmt.Errorf("CreateSubmission failed: %v", err) + return nil, err } - { - type swiftcRequestData struct { - MaxDuration int `json:"max_duration_ms"` - Code string `json:"code"` - } - type swiftcResponseData struct { - Result string `json:"result"` - Stdout string `json:"stdout"` - Stderr string `json:"stderr"` - } - reqData := swiftcRequestData{ - MaxDuration: 5000, - Code: payload.Code, - } - reqJson, err := json.Marshal(reqData) - if err != nil { - return fmt.Errorf("json.Marshal failed: %v", err) - } - res, err := http.Post("http://worker:80/api/swiftc", "application/json", bytes.NewBuffer(reqJson)) - if err != nil { - return fmt.Errorf("http.Post failed: %v", err) - } - resData := swiftcResponseData{} - if err := json.NewDecoder(res.Body).Decode(&resData); err != nil { - return fmt.Errorf("json.Decode failed: %v", err) - } - if resData.Result != "success" { - err := p.q.CreateTestcaseExecution(ctx, db.CreateTestcaseExecutionParams{ - SubmissionID: submissionID, - TestcaseID: nil, - Status: "compile_error", - Stdout: resData.Stdout, - Stderr: resData.Stderr, - }) - if err != nil { - return fmt.Errorf("CreateTestcaseExecution failed: %v", err) - } - p.c <- "compile_error" - return fmt.Errorf("swiftc failed: %v", resData.Stderr) - } - } - { - type wasmcRequestData struct { - MaxDuration int `json:"max_duration_ms"` - Code string `json:"code"` - } - type wasmcResponseData struct { - Result string `json:"result"` - Stdout string `json:"stdout"` - Stderr string `json:"stderr"` - } - reqData := wasmcRequestData{ - MaxDuration: 5000, - Code: payload.Code, - } - reqJson, err := json.Marshal(reqData) - if err != nil { - return fmt.Errorf("json.Marshal failed: %v", err) - } - res, err := http.Post("http://worker:80/api/wasmc", "application/json", bytes.NewBuffer(reqJson)) - if err != nil { - return fmt.Errorf("http.Post failed: %v", err) - } - resData := wasmcResponseData{} - if err := json.NewDecoder(res.Body).Decode(&resData); err != nil { - return fmt.Errorf("json.Decode failed: %v", err) - } - if resData.Result != "success" { - err := p.q.CreateTestcaseExecution(ctx, db.CreateTestcaseExecutionParams{ - SubmissionID: submissionID, - TestcaseID: nil, - Status: "compile_error", - Stdout: resData.Stdout, - Stderr: resData.Stderr, - }) - if err != nil { - return fmt.Errorf("CreateTestcaseExecution failed: %v", err) - } - p.c <- "compile_error" - return fmt.Errorf("wasmc failed: %v", resData.Stderr) - } - } + return &TaskResultCreateSubmissionRecord{ + TaskPayload: payload, + SubmissionID: int(submissionID), + }, nil +} - testcases, err := p.q.ListTestcasesByGameID(ctx, int32(payload.GameID)) +func (p *processor) doProcessTaskCompileSwiftToWasm( + _ context.Context, + payload *TaskPayloadCompileSwiftToWasm, +) (*TaskResultCompileSwiftToWasm, error) { + type swiftcRequestData struct { + MaxDuration int `json:"max_duration_ms"` + Code string `json:"code"` + } + type swiftcResponseData struct { + Status string `json:"status"` + Stdout string `json:"stdout"` + Stderr string `json:"stderr"` + } + reqData := swiftcRequestData{ + MaxDuration: 5000, + Code: payload.Code(), + } + reqJson, err := json.Marshal(reqData) if err != nil { - return fmt.Errorf("ListTestcasesByGameID failed: %v", err) + return nil, fmt.Errorf("json.Marshal failed: %v", err) } - - for _, testcase := range testcases { - type testrunRequestData struct { - MaxDuration int `json:"max_duration_ms"` - Code string `json:"code"` - Stdin string `json:"stdin"` - } - type testrunResponseData struct { - Result string `json:"result"` - Stdout string `json:"stdout"` - Stderr string `json:"stderr"` - } - reqData := testrunRequestData{ - MaxDuration: 5000, - Code: payload.Code, - Stdin: testcase.Stdin, - } - reqJson, err := json.Marshal(reqData) - if err != nil { - return fmt.Errorf("json.Marshal failed: %v", err) - } - res, err := http.Post("http://worker:80/api/testrun", "application/json", bytes.NewBuffer(reqJson)) - if err != nil { - return fmt.Errorf("http.Post failed: %v", err) - } - resData := testrunResponseData{} - if err := json.NewDecoder(res.Body).Decode(&resData); err != nil { - return fmt.Errorf("json.Decode failed: %v", err) - } - if resData.Result != "success" { - err := p.q.CreateTestcaseExecution(ctx, db.CreateTestcaseExecutionParams{ - SubmissionID: submissionID, - TestcaseID: &testcase.TestcaseID, - Status: resData.Result, - Stdout: resData.Stdout, - Stderr: resData.Stderr, - }) - if err != nil { - return fmt.Errorf("CreateTestcaseExecution failed: %v", err) - } - p.c <- resData.Result - return fmt.Errorf("testrun failed: %v", resData.Stderr) - } - if !isTestcaseExecutionCorrect(testcase.Stdout, resData.Stdout) { - err := p.q.CreateTestcaseExecution(ctx, db.CreateTestcaseExecutionParams{ - SubmissionID: submissionID, - TestcaseID: &testcase.TestcaseID, - Status: "wrong_answer", - Stdout: resData.Stdout, - Stderr: resData.Stderr, - }) - if err != nil { - return fmt.Errorf("CreateTestcaseExecution failed: %v", err) - } - p.c <- "wrong_answer" - return fmt.Errorf("testrun failed: %v", resData.Stdout) - } + res, err := http.Post("http://worker:80/api/swiftc", "application/json", bytes.NewBuffer(reqJson)) + if err != nil { + return nil, fmt.Errorf("http.Post failed: %v", err) + } + resData := swiftcResponseData{} + if err := json.NewDecoder(res.Body).Decode(&resData); err != nil { + return nil, fmt.Errorf("json.Decode failed: %v", err) } + return &TaskResultCompileSwiftToWasm{ + TaskPayload: payload, + Status: resData.Status, + Stdout: resData.Stdout, + Stderr: resData.Stderr, + }, nil +} - p.c <- "success" - return nil +func (p *processor) doProcessTaskCompileWasmToNativeExecutable( + _ context.Context, + payload *TaskPayloadCompileWasmToNativeExecutable, +) (*TaskResultCompileWasmToNativeExecutable, error) { + type wasmcRequestData struct { + MaxDuration int `json:"max_duration_ms"` + Code string `json:"code"` + } + type wasmcResponseData struct { + Status string `json:"status"` + Stdout string `json:"stdout"` + Stderr string `json:"stderr"` + } + reqData := wasmcRequestData{ + MaxDuration: 5000, + Code: payload.Code(), + } + reqJson, err := json.Marshal(reqData) + if err != nil { + return nil, fmt.Errorf("json.Marshal failed: %v", err) + } + res, err := http.Post("http://worker:80/api/wasmc", "application/json", bytes.NewBuffer(reqJson)) + if err != nil { + return nil, fmt.Errorf("http.Post failed: %v", err) + } + resData := wasmcResponseData{} + if err := json.NewDecoder(res.Body).Decode(&resData); err != nil { + return nil, fmt.Errorf("json.Decode failed: %v", err) + } + return &TaskResultCompileWasmToNativeExecutable{ + TaskPayload: payload, + Status: resData.Status, + Stdout: resData.Stdout, + Stderr: resData.Stderr, + }, nil } -func isTestcaseExecutionCorrect(expectedStdout, actualStdout string) bool { - expectedStdout = strings.TrimSpace(expectedStdout) - actualStdout = strings.TrimSpace(actualStdout) - return actualStdout == expectedStdout +func (p *processor) doProcessTaskRunTestcase( + _ context.Context, + payload *TaskPayloadRunTestcase, +) (*TaskResultRunTestcase, error) { + type testrunRequestData struct { + MaxDuration int `json:"max_duration_ms"` + Code string `json:"code"` + Stdin string `json:"stdin"` + } + type testrunResponseData struct { + Status string `json:"status"` + Stdout string `json:"stdout"` + Stderr string `json:"stderr"` + } + reqData := testrunRequestData{ + MaxDuration: 5000, + Code: payload.Code(), + Stdin: payload.Stdin, + } + reqJson, err := json.Marshal(reqData) + if err != nil { + return nil, fmt.Errorf("json.Marshal failed: %v", err) + } + res, err := http.Post("http://worker:80/api/testrun", "application/json", bytes.NewBuffer(reqJson)) + if err != nil { + return nil, fmt.Errorf("http.Post failed: %v", err) + } + resData := testrunResponseData{} + if err := json.NewDecoder(res.Body).Decode(&resData); err != nil { + return nil, fmt.Errorf("json.Decode failed: %v", err) + } + return &TaskResultRunTestcase{ + TaskPayload: payload, + Status: resData.Status, + Stdout: resData.Stdout, + Stderr: resData.Stderr, + }, nil } |
