Skip to content

Latest commit

 

History

History
120 lines (81 loc) · 6.65 KB

File metadata and controls

120 lines (81 loc) · 6.65 KB

Webapp

Remix 2.1.0 app serving as the main API, dashboard, and orchestration engine. Uses an Express server (server.ts).

Verifying Changes

Never run pnpm run build --filter webapp to verify changes. Building proves almost nothing about correctness. The webapp is an app, not a public package — use typecheck from the repo root:

pnpm run typecheck --filter webapp   # ~1-2 minutes

Only run typecheck after major changes (new files, significant refactors, schema changes). For small edits, trust the types and let CI catch issues.

Note: Public packages (packages/*) use build instead. See the root CLAUDE.md for details.

Testing Dashboard Changes with Chrome DevTools MCP

Use the chrome-devtools MCP server to visually verify local dashboard changes. The webapp must be running (pnpm run dev --filter webapp from repo root).

Login

1. mcp__chrome-devtools__new_page(url: "http://localhost:3030")
   → Redirects to /login
2. mcp__chrome-devtools__click the "Continue with Email" link
3. mcp__chrome-devtools__fill the email field with "local@trigger.dev"
4. mcp__chrome-devtools__click "Send a magic link"
   → Auto-logs in and redirects to the dashboard (no email verification needed locally)

Navigating and Verifying

  • take_snapshot: Get an a11y tree of the page (text content, element UIDs for interaction). Prefer this over screenshots for understanding page structure.
  • take_screenshot: Capture what the page looks like visually. Use to verify styling, layout, and visual changes.
  • navigate_page: Go to specific URLs, e.g. http://localhost:3030/orgs/references-bc08/projects/hello-world-SiWs/env/dev/runs
  • click / fill: Interact with elements using UIDs from take_snapshot.
  • evaluate_script: Run JS in the browser console for debugging.
  • list_console_messages: Check for console errors after navigating.

Tips

  • Snapshots can be very large on complex pages (200K+ chars). Use take_screenshot first to orient, then take_snapshot only when you need element UIDs to interact.
  • The local seeded user email is local@trigger.dev.
  • Dashboard URL pattern: http://localhost:3030/orgs/{orgSlug}/projects/{projectSlug}/env/{envSlug}/{section}

Key File Locations

  • Trigger API: app/routes/api.v1.tasks.$taskId.trigger.ts
  • Batch trigger: app/routes/api.v1.tasks.batch.ts
  • OTEL endpoints: app/routes/otel.v1.logs.ts, app/routes/otel.v1.traces.ts
  • Prisma setup: app/db.server.ts
  • Run engine config: app/v3/runEngine.server.ts
  • Services: app/v3/services/**/*.server.ts
  • Presenters: app/v3/presenters/**/*.server.ts

Route Convention

Routes use Remix flat-file convention with dot-separated segments: api.v1.tasks.$taskId.trigger.ts -> /api/v1/tasks/:taskId/trigger

Environment Variables

Access via env export from app/env.server.ts. Never use process.env directly.

For testable code, never import env.server.ts in test files. Pass configuration as options instead:

  • realtimeClient.server.ts (testable service, takes config as constructor arg)
  • realtimeClientGlobal.server.ts (creates singleton with env config)

Run Engine 2.0

The webapp integrates @internal/run-engine via app/v3/runEngine.server.ts. This is the singleton engine instance. Services in app/v3/services/ call engine methods for all run lifecycle operations (triggering, completing, cancelling, etc.).

The engineVersion.server.ts file determines V1 vs V2 for a given environment. New code should always target V2.

Background Workers

Background job workers use @trigger.dev/redis-worker:

  • app/v3/commonWorker.server.ts
  • app/v3/alertsWorker.server.ts
  • app/v3/batchTriggerWorker.server.ts

Do NOT add new jobs using zodworker/graphile-worker (legacy).

Real-time

  • Socket.io: app/v3/handleSocketIo.server.ts, app/v3/handleWebsockets.server.ts
  • Electric SQL: Powers real-time data sync for the dashboard

Legacy V1 Code

The app/v3/ directory name is misleading - most code is actively used by V2. Only these specific files are V1-only legacy:

  • app/v3/marqs/ (old MarQS queue system)
  • app/v3/legacyRunEngineWorker.server.ts
  • app/v3/services/triggerTaskV1.server.ts
  • app/v3/services/cancelTaskRunV1.server.ts
  • app/v3/authenticatedSocketConnection.server.ts
  • app/v3/sharedSocketConnection.ts

Some services (e.g., cancelTaskRun.server.ts, batchTriggerV3.server.ts) branch on RunEngineVersion to support both V1 and V2. When editing these, only modify V2 code paths.

Performance: Trigger Hot Path

The triggerTask.server.ts service is the highest-throughput code path in the system. Every API trigger call goes through it. Keep it fast:

  • Do NOT add database queries to triggerTask.server.ts or batchTriggerV3.server.ts. Task defaults (TTL, etc.) are resolved via backgroundWorkerTask.findFirst() in the queue concern (queues.server.ts) - one query per request, in mutually exclusive branches depending on locked/non-locked path. Piggyback on the existing query instead of adding new ones.
  • Two-stage resolution pattern: Task metadata is resolved in two stages by design:
    1. Trigger time (triggerTask.server.ts): Only TTL is resolved from task defaults. Everything else uses whatever the caller provides.
    2. Dequeue time (dequeueSystem.ts): Full BackgroundWorkerTask is loaded and retry config, machine config, maxDuration, etc. are resolved against task defaults.
  • If you need to add a new task-level default, add it to the existing select clause in the backgroundWorkerTask.findFirst() query — do NOT add a second query. If the default doesn't need to be known at trigger time, resolve it at dequeue time instead.
  • Batch triggers (batchTriggerV3.server.ts) follow the same pattern — keep batch paths equally fast.

Prisma Query Patterns

  • Always use findFirst instead of findUnique. Prisma's findUnique has an implicit DataLoader that batches concurrent calls into a single IN query. This batching cannot be disabled and has active bugs even in Prisma 6.x: uppercase UUIDs returning null (#25484, confirmed 6.4.1), composite key SQL correctness issues (#22202), and 5-10x worse performance than manual DataLoader (#6573, open since 2021). findFirst is never batched and avoids this entire class of issues.

React Patterns

  • Only use useCallback/useMemo for context provider values, expensive derived data that is a dependency elsewhere, or stable refs required by a dependency array. Don't wrap ordinary event handlers or trivial computations.
  • Use named constants for sentinel/placeholder values (e.g. const UNSET_VALUE = "__unset__") instead of raw string literals scattered across comparisons.