From f6687a6c3412b1483e700834d628e1ff6b323cf3 Mon Sep 17 00:00:00 2001 From: "remote-swe-app[bot]" <123456+remote-swe-app[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 08:39:54 +0000 Subject: [PATCH 1/3] docs: add asynchronous jobs section to webapp README --- webapp/README.md | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/webapp/README.md b/webapp/README.md index 99b1e93..b947583 100644 --- a/webapp/README.md +++ b/webapp/README.md @@ -185,3 +185,68 @@ This project uses type-safe server actions with authentication: ); } ``` + +### Asynchronous Jobs + +Asynchronous jobs are Lambda functions that handle long-running or background tasks. The `job.Dockerfile` builds all TypeScript files in `src/jobs/` into separate Lambda handlers using `esbuild src/jobs/*.ts --bundle`. + +**Project structure:** + +For simple jobs, place a single file directly under `src/jobs/`: + +``` +webapp/src/jobs/ +├── migration-runner.ts # Single-file Lambda handler +└── async-job-runner.ts # Single-file Lambda handler +``` + +For jobs with complex logic, use a subdirectory: + +``` +webapp/src/jobs/ +├── async-job-runner.ts # Lambda handler entry point +└── async-job/ # Business logic directory + └── translate.ts # Job implementation +``` + +**Example implementation:** + +```typescript +// webapp/src/jobs/async-job-runner.ts +import { translateJobHandler, translateJobSchema } from '@/jobs/async-job/translate'; +import { Handler } from 'aws-lambda'; +import { z } from 'zod'; + +const jobPayloadPropsSchema = z.discriminatedUnion('type', [ + translateJobSchema, + // Add more job types here +]); + +export const handler: Handler = async (event) => { + const { data: payload, error } = jobPayloadPropsSchema.safeParse(event); + if (error) throw new Error(error.toString()); + + switch (payload.type) { + case 'translate': + await translateJobHandler(payload); + break; + } +}; +``` + +```typescript +// webapp/src/jobs/async-job/translate.ts +import { z } from 'zod'; + +export const translateJobSchema = z.object({ + type: z.literal('translate'), + todoItemId: z.string(), + userId: z.string(), +}); + +export const translateJobHandler = async (params: z.infer) => { + // Job implementation +}; +``` + +**Note:** All jobs share the same `job.Dockerfile`. No individual Dockerfiles are needed. To deploy jobs, configure them in the CDK stack (see `cdk/lib/constructs/async-job.ts`). From cae3e93a93fdc9f11f47ef03c0065de1f540dc52 Mon Sep 17 00:00:00 2001 From: "remote-swe-app[bot]" <123456+remote-swe-app[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 08:42:12 +0000 Subject: [PATCH 2/3] docs: remove code examples and add CDK entry point override explanation --- webapp/README.md | 46 +++++++++------------------------------------- 1 file changed, 9 insertions(+), 37 deletions(-) diff --git a/webapp/README.md b/webapp/README.md index b947583..bd1cea6 100644 --- a/webapp/README.md +++ b/webapp/README.md @@ -190,7 +190,7 @@ This project uses type-safe server actions with authentication: Asynchronous jobs are Lambda functions that handle long-running or background tasks. The `job.Dockerfile` builds all TypeScript files in `src/jobs/` into separate Lambda handlers using `esbuild src/jobs/*.ts --bundle`. -**Project structure:** +**File structure:** For simple jobs, place a single file directly under `src/jobs/`: @@ -209,44 +209,16 @@ webapp/src/jobs/ └── translate.ts # Job implementation ``` -**Example implementation:** +**Deployment:** -```typescript -// webapp/src/jobs/async-job-runner.ts -import { translateJobHandler, translateJobSchema } from '@/jobs/async-job/translate'; -import { Handler } from 'aws-lambda'; -import { z } from 'zod'; - -const jobPayloadPropsSchema = z.discriminatedUnion('type', [ - translateJobSchema, - // Add more job types here -]); - -export const handler: Handler = async (event) => { - const { data: payload, error } = jobPayloadPropsSchema.safeParse(event); - if (error) throw new Error(error.toString()); - - switch (payload.type) { - case 'translate': - await translateJobHandler(payload); - break; - } -}; -``` +All jobs share the same `job.Dockerfile`. The CDK stack overrides the entry point using the `cmd` parameter in `DockerImageCode.fromImageAsset()`: ```typescript -// webapp/src/jobs/async-job/translate.ts -import { z } from 'zod'; - -export const translateJobSchema = z.object({ - type: z.literal('translate'), - todoItemId: z.string(), - userId: z.string(), -}); - -export const translateJobHandler = async (params: z.infer) => { - // Job implementation -}; +// Example from cdk/lib/constructs/async-job.ts +code: DockerImageCode.fromImageAsset(join('..', 'webapp'), { + cmd: ['async-job-runner.handler'], // Override the default CMD + file: 'job.Dockerfile', +}) ``` -**Note:** All jobs share the same `job.Dockerfile`. No individual Dockerfiles are needed. To deploy jobs, configure them in the CDK stack (see `cdk/lib/constructs/async-job.ts`). +This allows multiple Lambda functions to use the same Docker image with different handlers. From 24c36ee0a8aa9dee63df7808acab5f77ebae32d1 Mon Sep 17 00:00:00 2001 From: "remote-swe-app[bot]" <123456+remote-swe-app[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 09:42:32 +0000 Subject: [PATCH 3/3] docs: make subdirectory pattern the standard for async jobs --- webapp/README.md | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/webapp/README.md b/webapp/README.md index bd1cea6..07c9c4f 100644 --- a/webapp/README.md +++ b/webapp/README.md @@ -188,30 +188,24 @@ This project uses type-safe server actions with authentication: ### Asynchronous Jobs -Asynchronous jobs are Lambda functions that handle long-running or background tasks. The `job.Dockerfile` builds all TypeScript files in `src/jobs/` into separate Lambda handlers using `esbuild src/jobs/*.ts --bundle`. +Asynchronous jobs are Lambda functions that handle long-running or background tasks. All async jobs are invoked through a single Lambda function (`async-job-runner.ts`) and can be triggered manually or as scheduled jobs. **File structure:** -For simple jobs, place a single file directly under `src/jobs/`: +Place each job's implementation in a subdirectory under `src/jobs/`: ``` webapp/src/jobs/ -├── migration-runner.ts # Single-file Lambda handler -└── async-job-runner.ts # Single-file Lambda handler -``` - -For jobs with complex logic, use a subdirectory: - -``` -webapp/src/jobs/ -├── async-job-runner.ts # Lambda handler entry point -└── async-job/ # Business logic directory +├── async-job-runner.ts # Lambda handler entry point (dispatches to jobs) +└── async-job/ # Job implementations directory └── translate.ts # Job implementation ``` +The `async-job-runner.ts` handler dispatches to the appropriate job based on the event payload type. + **Deployment:** -All jobs share the same `job.Dockerfile`. The CDK stack overrides the entry point using the `cmd` parameter in `DockerImageCode.fromImageAsset()`: +The `job.Dockerfile` builds all TypeScript files in `src/jobs/` using `esbuild src/jobs/*.ts --bundle`. The CDK stack overrides the entry point using the `cmd` parameter: ```typescript // Example from cdk/lib/constructs/async-job.ts