-
-
Notifications
You must be signed in to change notification settings - Fork 2
Feature/appbuilder-grader #84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
d7cbf69
2ed2728
0c8eaf1
7439df4
b8c1532
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| -- CreateTable | ||
| CREATE TABLE "public"."gradingResult" ( | ||
| "uuid" UUID NOT NULL, | ||
| "project_id" INTEGER NOT NULL, | ||
| "status" VARCHAR(255), | ||
| "result" VARCHAR(2000), | ||
| "publisher_id" VARCHAR(255) NOT NULL, | ||
| "lambda_request_id" VARCHAR(255), | ||
| "created" TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP, | ||
| "updated" TIMESTAMP(6), | ||
|
|
||
| CONSTRAINT "gradingResult_pkey" PRIMARY KEY ("uuid") | ||
| ); | ||
|
|
||
| -- CreateIndex | ||
| CREATE INDEX "idx_grading_result_project_id" ON "public"."gradingResult"("project_id"); | ||
|
|
||
| -- AddForeignKey | ||
| ALTER TABLE "public"."gradingResult" ADD CONSTRAINT "fk_grading_result_project_id" FOREIGN KEY ("project_id") REFERENCES "public"."project"("id") ON DELETE NO ACTION ON UPDATE NO ACTION; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,7 @@ generator client { | |
|
|
||
| datasource db { | ||
| provider = "postgresql" | ||
| url = env("DATABASE_URL") | ||
| url = env("DATABASE_URL") | ||
| } | ||
|
|
||
| model build { | ||
|
|
@@ -62,21 +62,22 @@ model job { | |
| } | ||
|
|
||
| model project { | ||
| id Int @id @default(autoincrement()) | ||
| status String? @db.VarChar(255) | ||
| result String? @db.VarChar(255) | ||
| error String? @db.VarChar(2083) | ||
| url String? @db.VarChar(1024) | ||
| user_id String? @db.VarChar(255) // ISSUE #77: remove this? | ||
| group_id String? @db.VarChar(255) // ISSUE #77: remove this? | ||
| app_id String? @db.VarChar(255) | ||
| project_name String? @db.VarChar(255) | ||
| language_code String? @db.VarChar(255) | ||
| publishing_key String? @db.VarChar(1024) // ISSUE #77: remove this? | ||
| created DateTime? @default(now()) @db.Timestamp(6) | ||
| updated DateTime? @updatedAt @db.Timestamp(6) | ||
| id Int @id @default(autoincrement()) | ||
| status String? @db.VarChar(255) | ||
| result String? @db.VarChar(255) | ||
| error String? @db.VarChar(2083) | ||
| url String? @db.VarChar(1024) | ||
| user_id String? @db.VarChar(255) // ISSUE #77: remove this? | ||
| group_id String? @db.VarChar(255) // ISSUE #77: remove this? | ||
| app_id String? @db.VarChar(255) | ||
| project_name String? @db.VarChar(255) | ||
| language_code String? @db.VarChar(255) | ||
| publishing_key String? @db.VarChar(1024) // ISSUE #77: remove this? | ||
| created DateTime? @default(now()) @db.Timestamp(6) | ||
| updated DateTime? @updatedAt @db.Timestamp(6) | ||
| client_id Int? | ||
| client client? @relation(fields: [client_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "fk_project_client_id") | ||
| gradingResult gradingResult[] | ||
| client client? @relation(fields: [client_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "fk_project_client_id") | ||
|
|
||
| @@index([client_id], map: "idx_project_client_id") | ||
| } | ||
|
|
@@ -112,3 +113,17 @@ model appVersion { | |
| created DateTime @default(now()) @db.Timestamp(6) | ||
| updated DateTime? @updatedAt @db.Timestamp(6) | ||
| } | ||
|
|
||
| model gradingResult { | ||
| uuid String @id @default(uuid()) @db.Uuid | ||
| project_id Int | ||
| status String? @db.VarChar(255) | ||
| result String? @db.VarChar(2000) | ||
| publisher_id String @db.VarChar(255) | ||
| lambda_request_id String? @db.VarChar(255) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this the right length limit? I don't know how best to verify this.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch. This could be a char(36) |
||
| created DateTime? @default(now()) @db.Timestamp(6) | ||
| updated DateTime? @updatedAt @db.Timestamp(6) | ||
| project project @relation(fields: [project_id], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "fk_grading_result_project_id") | ||
|
|
||
| @@index([project_id], map: "idx_grading_result_project_id") | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| import { InvokeCommand, LambdaClient } from '@aws-sdk/client-lambda'; | ||
| import { SpanStatusCode, trace } from '@opentelemetry/api'; | ||
| import { AWSVars } from './vars'; | ||
|
|
||
| const tracer = trace.getTracer('Lambda'); | ||
|
|
||
| export class Lambda { | ||
| private client; | ||
|
|
||
| public constructor() { | ||
| this.client = new LambdaClient({ region: AWSVars.artifactsRegion() }); | ||
| } | ||
|
|
||
| public async invokeJson<TPayload extends Record<string, unknown>>( | ||
| functionName: string, | ||
| payload: TPayload | ||
| ) { | ||
| return tracer.startActiveSpan('Lambda - Invoke', async (span) => { | ||
| span.setAttributes({ | ||
| 'lambda.function-name': functionName, | ||
| 'lambda.payload': JSON.stringify(payload) | ||
| }); | ||
| try { | ||
| const startTime = Date.now(); | ||
| const result = await this.client.send( | ||
| new InvokeCommand({ | ||
| FunctionName: functionName, | ||
| InvocationType: 'RequestResponse', | ||
| Payload: Buffer.from(JSON.stringify(payload)) | ||
| }) | ||
| ); | ||
| span.setAttributes({ | ||
| 'lambda.status-code': result.StatusCode, | ||
| 'lambda.executed-version': result.ExecutedVersion ?? '', | ||
| 'lambda.function-error': result.FunctionError ?? '', | ||
| 'lambda.executionTimeMs': Date.now() - startTime | ||
| }); | ||
|
|
||
| const body = result.Payload ? Buffer.from(result.Payload).toString('utf8') : ''; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Passing an empty string to parsePayload will always result in an error. Is this what we want?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Payload should never be falsey at this point, but if it is, an empty string is falsey on the next line and parsePayload should not run unless I'm missing something. |
||
| const parsed = body ? this.parsePayload(body) : null; | ||
| return { | ||
| requestId: result.$metadata.requestId ?? null, | ||
| payload: parsed | ||
| }; | ||
| } catch (e) { | ||
| span.recordException(e as Error); | ||
| span.setStatus({ | ||
| code: SpanStatusCode.ERROR, | ||
| message: (e as Error).message | ||
| }); | ||
| throw e; | ||
| } finally { | ||
| span.end(); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| private parsePayload(body: string) { | ||
| try { | ||
| return JSON.parse(body) as Record<string, unknown>; | ||
| } catch { | ||
| throw new Error(`Lambda returned invalid JSON: ${body}`); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this the right length limit? I don't know how best to verify this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an arbitrary number intended to be bigger than any reasonable value. Only an error could be larger and after trimming there should be plenty of information there still. I'm not opposed to changing this though if you want to.