Skip to content

Conversation

ericallam
Copy link
Member

No description provided.

Copy link

changeset-bot bot commented Oct 3, 2025

⚠️ No Changeset found

Latest commit: d77249c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link
Contributor

coderabbitai bot commented Oct 3, 2025

Walkthrough

  • Added helper formatClickhouseUnsignedIntegerString to normalize non-negative duration serialization for number and bigint, replacing prior toString usages in ClickHouse event writes.
  • calculateDurationFromStart now accepts an optional minimumDuration parameter and clamps computed duration to it when provided.
  • Some duration paths now pass a default minimumDuration of 100_000_000 when endTime is provided; branches without endTime retain a static default of 100.
  • Switched run lookup in findRunForEventCreation from $replica.taskRun.findFirst to prisma.taskRun.findFirst.
  • In runRetryScheduled, added an early return when time >= retryAt and adjusted retry label to show previous attempt number.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request lacks any description and does not follow the repository’s required template, missing the issue reference, checklist, testing steps, changelog, and screenshots. Without these sections, reviewers cannot understand the context, verify that contribution guidelines were followed, or see how the changes were tested. This omission hinders effective evaluation and merging of the PR. Add a pull request description using the repository template by including the issue number, completed checklist, detailed testing steps, a concise changelog entry, and any relevant screenshots.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly identifies the main change in the pull request, which is preventing spans from having negative durations by introducing clamping logic and a formatting helper. It follows the conventional fix(scope): description format, making the purpose clear. While the PR also includes additional unrelated refactors, the title accurately conveys the primary fix.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ea-branch-96

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ericallam ericallam merged commit cdd1a88 into main Oct 3, 2025
30 of 31 checks passed
@ericallam ericallam deleted the ea-branch-96 branch October 3, 2025 13:50
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
apps/webapp/app/v3/runEngineHandlers.server.ts (1)

410-412: Retry label could render “#0” — verify semantics

If run.attemptNumber === 1, this prints “#0”. If the intent is “previous attempt,” consider clamping or hiding when result < 1.

Example fix:

-      let retryMessage = `Retry ${
-        typeof run.attemptNumber === "number" ? `#${run.attemptNumber - 1}` : ""
-      } delay`;
+      const previous = typeof run.attemptNumber === "number" ? run.attemptNumber - 1 : undefined;
+      let retryMessage = `Retry ${previous && previous > 0 ? `#${previous}` : ""} delay`;
apps/webapp/app/v3/eventRepository/clickhouseEventRepository.server.ts (1)

435-438: Mixed minimums: endTime path uses 100ms, non‑endTime path uses 100 (ns)

Confirm this asymmetry is intentional. If not, consider standardizing the lower bound (e.g., 100ms) for consistency in analytics and UI bars.

Also applies to: 465-466

apps/webapp/app/v3/eventRepository/common.server.ts (1)

31-45: Clamp logic OK; improve precision and guard checks

  • Use precise BigInt math to avoid number precision loss.
  • Treat minimumDuration = 0 correctly.
  • Optional: either remove the string branch or widen the type.

Suggested change:

-export function calculateDurationFromStart(
-  startTime: bigint,
-  endTime: Date = new Date(),
-  minimumDuration?: number
-) {
-  const $endtime = typeof endTime === "string" ? new Date(endTime) : endTime;
-
-  const duration = Number(BigInt($endtime.getTime() * 1_000_000) - startTime);
-
-  if (minimumDuration && duration < minimumDuration) {
-    return minimumDuration;
-  }
-
-  return duration;
-}
+export function calculateDurationFromStart(
+  startTime: bigint,
+  endTime: Date /* | string */ = new Date(),
+  minimumDuration?: number
+) {
+  // If you intend to accept strings, widen the type; otherwise drop this branch.
+  const $endtime = typeof endTime === "string" ? new Date(endTime) : endTime;
+  // Precise BigInt math, then convert to number
+  const endNs = BigInt($endtime.getTime()) * 1_000_000n;
+  const duration = Number(endNs - startTime);
+  if (minimumDuration != null && duration < minimumDuration) {
+    return minimumDuration;
+  }
+  return duration;
+}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 200b735 and d77249c.

📒 Files selected for processing (4)
  • apps/webapp/app/v3/eventRepository/clickhouseEventRepository.server.ts (11 hunks)
  • apps/webapp/app/v3/eventRepository/common.server.ts (1 hunks)
  • apps/webapp/app/v3/eventRepository/index.server.ts (2 hunks)
  • apps/webapp/app/v3/runEngineHandlers.server.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Always prefer using isomorphic code like fetch, ReadableStream, etc. instead of Node.js specific code
For TypeScript, we usually use types over interfaces
Avoid enums
No default exports, use function declarations

Files:

  • apps/webapp/app/v3/eventRepository/index.server.ts
  • apps/webapp/app/v3/eventRepository/clickhouseEventRepository.server.ts
  • apps/webapp/app/v3/eventRepository/common.server.ts
  • apps/webapp/app/v3/runEngineHandlers.server.ts
{packages/core,apps/webapp}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

We use zod a lot in packages/core and in the webapp

Files:

  • apps/webapp/app/v3/eventRepository/index.server.ts
  • apps/webapp/app/v3/eventRepository/clickhouseEventRepository.server.ts
  • apps/webapp/app/v3/eventRepository/common.server.ts
  • apps/webapp/app/v3/runEngineHandlers.server.ts
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

When importing from @trigger.dev/core in the webapp, never import the root package path; always use one of the documented subpath exports from @trigger.dev/core’s package.json

Files:

  • apps/webapp/app/v3/eventRepository/index.server.ts
  • apps/webapp/app/v3/eventRepository/clickhouseEventRepository.server.ts
  • apps/webapp/app/v3/eventRepository/common.server.ts
  • apps/webapp/app/v3/runEngineHandlers.server.ts
{apps/webapp/app/**/*.server.{ts,tsx},apps/webapp/app/routes/**/*.ts}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access environment variables only via the env export from app/env.server.ts; do not reference process.env directly

Files:

  • apps/webapp/app/v3/eventRepository/index.server.ts
  • apps/webapp/app/v3/eventRepository/clickhouseEventRepository.server.ts
  • apps/webapp/app/v3/eventRepository/common.server.ts
  • apps/webapp/app/v3/runEngineHandlers.server.ts
apps/webapp/app/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Modules intended for test consumption under apps/webapp/app/**/*.ts must not read environment variables; accept configuration via options instead

Files:

  • apps/webapp/app/v3/eventRepository/index.server.ts
  • apps/webapp/app/v3/eventRepository/clickhouseEventRepository.server.ts
  • apps/webapp/app/v3/eventRepository/common.server.ts
  • apps/webapp/app/v3/runEngineHandlers.server.ts
🧠 Learnings (1)
📚 Learning: 2025-07-12T18:06:04.133Z
Learnt from: matt-aitken
PR: triggerdotdev/trigger.dev#2264
File: apps/webapp/app/services/runsRepository.server.ts:172-174
Timestamp: 2025-07-12T18:06:04.133Z
Learning: In apps/webapp/app/services/runsRepository.server.ts, the in-memory status filtering after fetching runs from Prisma is intentionally used as a workaround for ClickHouse data delays. This approach is acceptable because the result set is limited to a maximum of 100 runs due to pagination, making the performance impact negligible.

Applied to files:

  • apps/webapp/app/v3/eventRepository/index.server.ts
🧬 Code graph analysis (2)
apps/webapp/app/v3/eventRepository/clickhouseEventRepository.server.ts (2)
apps/webapp/app/v3/eventRepository/eventRepository.server.ts (2)
  • event (118-149)
  • event (1088-1107)
apps/webapp/app/v3/eventRepository/common.server.ts (1)
  • calculateDurationFromStart (31-45)
apps/webapp/app/v3/runEngineHandlers.server.ts (1)
apps/webapp/app/v3/services/completeAttempt.server.ts (1)
  • run (419-517)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (3)
apps/webapp/app/v3/eventRepository/index.server.ts (1)

5-5: Switching to primary (prisma) for run lookup looks good

Using the primary for event-creation reads should reduce replica‑lag “RUN_NOT_FOUND” issues. Please confirm this is intentional for this hot path and acceptable from a read‑load perspective.

Also applies to: 148-171

apps/webapp/app/v3/runEngineHandlers.server.ts (1)

406-409: Early exit prevents negative-duration spans

Good guard. This avoids recording a span when now ≥ retryAt.

apps/webapp/app/v3/eventRepository/clickhouseEventRepository.server.ts (1)

159-160: LGTM: sanitize and normalize duration writes

Replacing raw toString() with formatClickhouseUnsignedIntegerString(...) across all write paths is the right move to prevent negative UInt values in ClickHouse. The changes here look consistent.

Also applies to: 465-466, 566-567, 600-601, 649-652, 699-702, 741-744, 789-792, 881-884

Comment on lines +1857 to +1867
function formatClickhouseUnsignedIntegerString(value: number | bigint): string {
if (value < 0) {
return "0";
}

if (typeof value === "bigint") {
return value.toString();
}

return Math.floor(value).toString();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Harden formatter against NaN/Infinity and negative BigInt

Currently, NaN/Infinity will serialize as "NaN"/"Infinity", causing ClickHouse insert failures. Also guard negative BigInts.

Apply:

-function formatClickhouseUnsignedIntegerString(value: number | bigint): string {
-  if (value < 0) {
-    return "0";
-  }
-
-  if (typeof value === "bigint") {
-    return value.toString();
-  }
-
-  return Math.floor(value).toString();
-}
+function formatClickhouseUnsignedIntegerString(value: number | bigint): string {
+  if (typeof value === "bigint") {
+    return value < 0n ? "0" : value.toString();
+  }
+  if (!Number.isFinite(value) || value <= 0) {
+    return "0";
+  }
+  const floored = Math.floor(value);
+  return floored <= 0 ? "0" : String(floored);
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function formatClickhouseUnsignedIntegerString(value: number | bigint): string {
if (value < 0) {
return "0";
}
if (typeof value === "bigint") {
return value.toString();
}
return Math.floor(value).toString();
}
function formatClickhouseUnsignedIntegerString(value: number | bigint): string {
if (typeof value === "bigint") {
return value < 0n ? "0" : value.toString();
}
if (!Number.isFinite(value) || value <= 0) {
return "0";
}
const floored = Math.floor(value);
return floored <= 0 ? "0" : String(floored);
}
🤖 Prompt for AI Agents
In apps/webapp/app/v3/eventRepository/clickhouseEventRepository.server.ts around
lines 1857 to 1867, the formatter currently allows NaN/Infinity and negative
BigInts to be serialized which breaks ClickHouse inserts; update the function to
first detect and return "0" for non-finite numbers (Number.isFinite(value) or
Number.isNaN checks) and for numbers that are finite use
Math.floor(value).toString(); for bigints, explicitly guard negative values
(value < 0n) and return "0" for negatives, otherwise return value.toString();
ensure the checks are ordered so typeof value === "bigint" is used for
BigInt-specific comparison and numbers are validated with isFinite/NaN before
flooring.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants