-
-
Notifications
You must be signed in to change notification settings - Fork 729
Improved schedule engine #2174
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
Improved schedule engine #2174
Conversation
|
WalkthroughThis change set introduces a major refactor and expansion of the scheduling and worker infrastructure in the codebase, centered around the introduction of a new internal package, ✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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.
Actionable comments posted: 14
🔭 Outside diff range comments (5)
internal-packages/run-engine/src/engine/types.ts (1)
128-137
: 💡 Verification agent🧩 Analysis chain
Temporal field proliferation – clarify semantics of
createdAt
vsqueuedAt
/queueTimestamp
TriggerParams
now exposes three very similar timestamps:
createdAt
queuedAt
queueTimestamp
Without a clear contract, callers may set only one of them or confuse their meaning, causing subtle ordering bugs in metrics or deduplication.
Suggest either:
- createdAt?: Date; + /** + * Absolute creation time of the *task run* record in the DB. + * Prefer `queuedAt` for queue-ing semantics and `queueTimestamp` for + * external-system hand-off. Documented here to avoid ambiguity. + */ + createdAt?: Date;and add JSDoc for the other two, or fold them into a single canonical field.
Run this to locate all writes to these properties:
🏁 Script executed:
#!/bin/bash rg -n --pretty $'(createdAt|queuedAt|queueTimestamp)\\s*:' | headLength of output: 296
🏁 Script executed:
#!/bin/bash set -euo pipefail # Check for queuedAt and queueTimestamp in TriggerParams type rg -n "queuedAt" internal-packages/run-engine/src/engine/types.ts || echo "no matches for queuedAt" rg -n "queueTimestamp" internal-packages/run-engine/src/engine/types.ts || echo "no matches for queueTimestamp"Length of output: 209
Enhance JSDoc for Temporal Fields in TriggerParams
The three timestamp fields in
TriggerParams
—createdAt
,queuedAt
, andqueueTimestamp
—currently lack documentation and have subtly different meanings. Please add clear JSDoc comments to each to prevent misuse:• File:
internal-packages/run-engine/src/engine/types.ts
Lines: ~108–137Suggested diff:
interface TriggerParams { + /** + * Absolute creation time of the task-run record in the database. + * Use only for DB-side ordering; not for queue sequencing. + */ createdAt?: Date; + /** + * Time when this run was enqueued in our internal scheduler. + * Use for internal queue ordering and deduplication. + */ queuedAt?: Date; + /** + * Time when the run was handed off to an external system or broker. + * Use for external-system metrics and hand-off tracing. + */ queueTimestamp?: Date; machine?: MachinePresetName; workerId?: string; runnerId?: string; releaseConcurrency?: boolean; runChainState?: RunChainState; scheduleId?: string; scheduleInstanceId?: string; }apps/webapp/app/v3/services/triggerTaskV1.server.ts (1)
367-372
: 🛠️ Refactor suggestionSame validation gap for
options.queueTimestamp
Duplicate the sanity check here (or extract a shared util) to avoid divergent behaviours between V1 and the new engine path.
internal-packages/schedule-engine/tsconfig.test.json (1)
1-22
:⚠️ Potential issue
include
misses the actual test folderIntegration tests live in
test/
, but"include": ["src/**/*.test.ts"]
only covers unit tests insidesrc/
.
vitest
will still run the file, yet the compiler won’t type-check it, defeating the purpose of this config.- "include": ["src/**/*.test.ts"], + "include": ["src/**/*.test.ts", "test/**/*.ts"],Add the glob (or move the tests) to ensure they’re compiled.
apps/webapp/app/v3/services/timeoutDeployment.server.ts (1)
46-63
: 🛠️ Refactor suggestion
tx
parameter is now unused – drop or use
enqueue()
still acceptstx?: PrismaClientOrTransaction
but never references it after the refactor tocommonWorker
.-static async enqueue( - deploymentId: string, - fromStatus: string, - errorMessage: string, - runAt: Date, - tx?: PrismaClientOrTransaction -) { +static async enqueue( + deploymentId: string, + fromStatus: string, + errorMessage: string, + runAt: Date, +) {Keeping an unused parameter risks confusion and lint warnings. If transactional enqueue is still required, wire it through
commonWorker.enqueue
; otherwise remove it.apps/webapp/app/v3/services/cancelDevSessionRuns.server.ts (1)
93-106
:⚠️ Potential issueBreaking change: parameter order flipped
enqueue()
used to be(options, tx, runAt?)
.
The new signature(options, runAt?, tx?)
silently swapsrunAt
andtx
. Existing call-sites will now pass a Prisma client where aDate
is expected, resulting in an invalidavailableAt
and no transactional context.Either restore the original ordering or add an overload while deprecating the old one:
-static async enqueue( - options: CancelDevSessionRunsServiceOptions, - runAt?: Date, - tx?: PrismaClientOrTransaction -) { +// Preserve old order +static async enqueue( + options: CancelDevSessionRunsServiceOptions, + tx?: PrismaClientOrTransaction, + runAt?: Date, +) {Remember to prefix
_tx
if it remains unused.
♻️ Duplicate comments (3)
apps/webapp/app/presenters/v3/RunListPresenter.server.ts (1)
182-186
: SameclampToNow
duplication as in NextRunListPresenterPlease pull this helper from a shared util to keep behaviour consistent across all call-sites and cut maintenance overhead.
internal-packages/schedule-engine/tsconfig.build.json (1)
6-8
: Same DOM lib concern as in tsconfig.src.jsonConsider trimming the
lib
array here as well to keep the build output consistent with the runtime environment.apps/webapp/app/v3/services/triggerTaskV1.server.ts (1)
442-443
: Conditionally includecreatedAt
Apply the same conditional spread pattern here to avoid sending explicit
undefined
to Prisma.
🧹 Nitpick comments (31)
apps/webapp/app/presenters/v3/NextRunListPresenter.server.ts (2)
192-195
: Utility duplication – extractclampToNow
clampToNow
is now copy-pasted in at least two presenters. Move it to a small shared util (e.g.~/utils/date.ts
) to avoid divergence and ease testing.-function clampToNow(date: Date): Date { - const now = new Date(); - return date > now ? now : date; -} +import { clampToNow } from "~/utils/date";
206-208
: Minor: avoid doubleDate
→number
→Date
conversions
time.from
/time.to
areDate
objects. You callclampToNow(time.to)
(returnsDate
) and then immediately.getTime()
. Consider inlining to keep it obvious:- to: time.to ? clampToNow(time.to).getTime() : undefined, + to: time.to ? Math.min(time.to.getTime(), Date.now()) : undefined,Purely cosmetic; feel free to skip.
apps/webapp/app/presenters/v3/RunListPresenter.server.ts (1)
291-294
: Performance & readability: calculate once
clampToNow(time.to)
is evaluated during SQL template construction; for large batches this inside-template computation is negligible, but calculating once improves clarity:- time.to - ? Prisma.sql`AND tr."createdAt" <= ${clampToNow(time.to).toISOString()}::timestamp` + time.to + ? Prisma.sql`AND tr."createdAt" <= ${ + clampToNow(time.to).toISOString() + }::timestamp`Even better after extracting util as suggested above.
internal-packages/schedule-engine/test/setup.ts (1)
1-4
: Consider moving global vitest config tovitest.config.*
instead of runtime mutation
vi.setConfig({ testTimeout: 60_000 });
works, but:
- It executes after test file import order, which can be flaky if other files rely on the timeout earlier.
- A
vitest.config.ts
(or<root>/vitest.setup.ts
referenced viasetupFiles
) is the canonical place.If you keep this, at least prefix the filename with
setupTests.
to make its intent clearer.apps/webapp/app/v3/services/triggerTask.server.ts (1)
34-36
: Consider surfacing docs / validation for the new options
queueTimestamp
andoverrideCreatedAt
are accepted here, but nothing verifies that:
queueTimestamp
≤overrideCreatedAt
(or vice-versa depending on intent)- both are sensible (e.g. not in the future or > now + max skew)
A short JSDoc comment or runtime guard would prevent subtle clock-skew bugs.
apps/webapp/app/v3/services/createBackgroundWorker.server.ts (1)
28-29
: Import is used only for side-effectful calls – keep tree-shaking friendly
scheduleEngine
is imported at module top level but only referenced insidesyncDeclarativeSchedules
.
For clarity / bundler friendliness you could move the import next to its usage:-import { scheduleEngine } from "../scheduleEngine.server"; +// defer import to keep the main bundle lean +import { scheduleEngine } from "../scheduleEngine.server";(Not critical; feel free to ignore if build size is not a concern.)
internal-packages/schedule-engine/tsconfig.json (1)
1-8
: Minor: missing"strict": true
&rootDir
can hurt DXSince this is a new package, enabling compiler strictness early saves bugs later:
"compilerOptions": { + "strict": true, "moduleResolution": "Node16", "module": "Node16", "customConditions": ["@triggerdotdev/source"] }
Also add
"rootDir": "./src"
to keep emitted paths tidy.internal-packages/schedule-engine/tsconfig.src.json (1)
6-8
: Unnecessary DOM libs increase type-check noiseThe library list includes
DOM*
libs even though the package runs exclusively in Node. This can:
- pull in thousands of irrelevant types
- mask accidental browser-only API usage
- "lib": ["ES2020", "DOM", "DOM.Iterable", "DOM.AsyncIterable"], + "lib": ["ES2020"],Unless you intentionally reference browser globals inside the engine, dropping them will speed up builds and tighten type safety.
apps/webapp/app/runEngine/services/triggerTask.server.ts (1)
311-312
: PassingcreatedAt
asundefined
clutters the Prisma payload
createdAt
is always present in the object, even when no override is supplied. Prisma acceptsundefined
, but it still bloats query text and hides intent.Consider making the property conditional:
- createdAt: options.overrideCreatedAt, + ...(options.overrideCreatedAt + ? { createdAt: options.overrideCreatedAt } + : {}),Keeps the payload minimal and future-proof if Prisma tightens strict-null-checks.
internal-packages/schedule-engine/src/engine/workerCatalog.ts (1)
3-14
: Explicit typing &as const
would safeguard the catalog
scheduleWorkerCatalog
is currently an untyped object literal. Down-stream code will lose IntelliSense and accidental property changes won’t be caught.-export const scheduleWorkerCatalog = { +import type { WorkerCatalog } from "@trigger.dev/worker"; // hypothetical shared type + +export const scheduleWorkerCatalog: WorkerCatalog = { "schedule.triggerScheduledTask": { schema: z.object({ instanceId: z.string(), exactScheduleTime: z.coerce.date(), }),Optionally append
as const
after the object to freeze the keys.This minor change prevents typos (e.g.,
"schedule.triggerSchedueldTask"
) from compiling.apps/webapp/app/services/email.server.ts (1)
95-101
: Return the enqueue promise to surface failures
scheduleEmail
currently awaits the enqueue but returnsvoid
, swallowing any value the worker library might provide (job id, etc.). Returning the promise enables callers to react or log the job id.-export async function scheduleEmail(data: DeliverEmail, delay?: { seconds: number }) { +export async function scheduleEmail( + data: DeliverEmail, + delay?: { seconds: number } +): Promise<void> { const availableAt = delay ? new Date(Date.now() + delay.seconds * 1000) : undefined; - await commonWorker.enqueue({ + return commonWorker.enqueue({ job: "scheduleEmail", payload: data, availableAt, }); }Also consider validating
delay.seconds >= 0
to avoid accidental past dates.internal-packages/schedule-engine/src/engine/distributedScheduling.ts (1)
21-26
: Small clarity nit
Math.pow(2, 31)
can be replaced with the more idiomatic2 ** 31
, which is easier to read and avoids an extra function call.apps/webapp/app/v3/commonWorker.server.ts (1)
48-141
: Catalog definition is getting unwieldyHard-coding dozens of job specs with identical
visibilityTimeoutMs
and very similar retry policies makes maintenance painful. Consider extracting helpers:const defaultJob = <T>(schema: T, retry = 5) => ({ schema, visibilityTimeoutMs: 60_000, retry: { maxAttempts: retry }, });Then:
catalog: { "v3.resumeBatchRun": defaultJob(z.object({ batchRunId: z.string() })), ... }This trims ~150 LOC and reduces copy-paste errors.
internal-packages/schedule-engine/README.md (2)
51-58
: Minor wording & brevity nit“from executing at exactly the same moment”
-Prevents thundering herd issues by distributing executions across time windows +Prevents thundering-herd issues by spreading executions across a time window🧰 Tools
🪛 LanguageTool
[style] ~51-~51: ‘exactly the same’ might be wordy. Consider a shorter alternative.
Context: ...t all scheduled tasks from executing at exactly the same moment: ```typescript import { calcula...(EN_WORDINESS_PREMIUM_EXACTLY_THE_SAME)
101-105
: Dangling colon renders as loose punctuationA colon at the start of a bullet occasionally shows up in some markdown renderers:
-- `redis`: Redis connection configuration ++ `redis` – Redis connection configuration🧰 Tools
🪛 LanguageTool
[uncategorized] ~101-~101: Loose punctuation mark.
Context: ...these configuration options: -prisma
: PrismaClient instance -redis
: Redis ...(UNLIKELY_OPENING_PUNCTUATION)
apps/webapp/app/v3/services/timeoutDeployment.server.ts (1)
53-62
: ConsiderenqueueOnce
to avoid duplicate timeout jobsTimeouts are idempotent; using plain
enqueue
can queue duplicates ifenqueue
is called multiple times before the first job is processed.- await commonWorker.enqueue({ + await commonWorker.enqueueOnce({ id: `timeoutDeployment:${deploymentId}`,The unique
id
is already provided, so switching toenqueueOnce
protects against accidental duplication at no extra cost.apps/webapp/app/v3/services/executeTasksWaitingForDeploy.ts (1)
107-116
: UseenqueueOnce
for id-based deduplicationAs with the timeout service, the job ID is deterministic (
v3.executeTasksWaitingForDeploy:${backgroundWorkerId}
).
Switching toenqueueOnce
guarantees exactly-once semantics during bursts (e.g., multiple deploy hooks firing).- return await commonWorker.enqueue({ + return await commonWorker.enqueueOnce({apps/webapp/app/v3/services/cancelTaskAttemptDependencies.server.ts (1)
60-69
: Unusedtx
parameter – silence linter or drop itThe
tx
argument is no longer forwarded tocommonWorker.enqueue
, leaving it unused and triggering the@typescript-eslint/no-unused-vars
rule in most code-bases.-static async enqueue(attemptId: string, tx: PrismaClientOrTransaction, runAt?: Date) { +static async enqueue( + attemptId: string, + _tx: PrismaClientOrTransaction, // keep positional compatibility but silence linter + runAt?: Date +) {If transactions are no longer required here, consider making the parameter optional and prefixing with an underscore (or removing it entirely) across call-sites to avoid confusion.
apps/webapp/app/runEngine/services/batchTrigger.server.ts (1)
316-321
:tx
parameter kept but never used
#enqueueBatchTaskRun()
still accepts atx
parameter yet the value is ignored after the switch tocommonWorker.enqueue
. Either remove the parameter or rename it to_tx
to clarify that it is intentionally unused:-async #enqueueBatchTaskRun(options: BatchProcessingOptions, tx?: PrismaClientOrTransaction) { +async #enqueueBatchTaskRun(options: BatchProcessingOptions, _tx?: PrismaClientOrTransaction) {Cleaning this up avoids false expectations that the call will be wrapped in a transaction.
apps/webapp/app/v3/services/resumeTaskDependency.server.ts (1)
157-171
: Unusedtx
argumentSimilar to other services,
tx
is accepted but not used after the move tocommonWorker.enqueue
.-static async enqueue( - dependencyId: string, - sourceTaskAttemptId: string, - tx: PrismaClientOrTransaction, - runAt?: Date -) { +static async enqueue( + dependencyId: string, + sourceTaskAttemptId: string, + _tx: PrismaClientOrTransaction, + runAt?: Date +) {This prevents linter warnings and signals that transactional support has been removed.
apps/webapp/test/distributedScheduling.test.ts (1)
57-88
: Potential flakiness in uniform-distribution assertionThe “should distribute work evenly” test uses 1 000 samples and fails if fewer than 80 % of 30 buckets receive at least one hit.
While unlikely, the deterministic hash could still cluster enough samples to dip below the 24-bucket threshold, making the test flaky.Consider loosening the assertion or increasing the sample size:
-const testCount = 1000; -… -expect(bucketsWithItems).toBeGreaterThan(distributionWindow * 0.8); +const testCount = 5_000; // reduces variance +… +expect(bucketsWithItems).toBeGreaterThan(distributionWindow * 0.7);This keeps the spirit of the check while minimising spurious CI failures.
apps/webapp/app/v3/services/resumeBatchRun.server.ts (1)
2-2
: Unused import side-effectSwitching to
commonWorker
makes thePrismaClientOrTransaction
argument inenqueue()
obsolete. Consider pruning that parameter from the method signature (and its call-sites) to avoid dead code and confusion.apps/webapp/app/v3/scheduleEngine.server.ts (1)
81-116
: Error is swallowed – add structured loggingThe
catch
only returns{ success:false }
but drops stack traces; production debugging will be painful.- } catch (error) { - return { - success: false, - error: error instanceof Error ? error.message : String(error), - }; + } catch (error) { + logger.error("scheduleEngine.onTriggerScheduledTask failed", { error }); + return { + success: false, + error: error instanceof Error ? error.message : String(error), + }; }apps/webapp/app/v3/services/batchTriggerV3.server.ts (2)
478-540
: Inconsistent logging & IDs reference “V2”This v3 service logs under
BatchTriggerV2
and builds job IDs withBatchTriggerV2Service.process
.
Rename toBatchTriggerV3
to avoid future grep/debug headaches.- id: `BatchTriggerV2Service.process:${options.batchId}:${options.processingId}`, + id: `BatchTriggerV3Service.process:${options.batchId}:${options.processingId}`,Same for every logger.debug message using
[BatchTriggerV2] …
.
895-899
:tx
parameter is never used
#enqueueBatchTaskRun
still acceptstx
but ignores it. Drop the argument or forward it to a transactional queue helper; leaving it dangling is misleading.internal-packages/schedule-engine/test/scheduleEngine.test.ts (1)
121-123
: Avoid brittle exact-equality on Date
expect(actualNextExecution).toEqual(expectedExecutionTime)
can flake by a few ms.
Use a ±1 s window ortoBeCloseTo
with a tolerance instead.internal-packages/schedule-engine/src/engine/types.ts (1)
27-30
: ConstrainlogLevel
via a union
logLevel?: string
accepts invalid values at runtime. ConsiderlogLevel?: "log" | "error" | "warn" | "info" | "debug";This mirrors the enum you use elsewhere and prevents typos.
apps/webapp/app/v3/services/upsertTaskSchedule.server.ts (2)
108-128
: Parallelise instance creation / registrationThe loop issues a Prisma insert then immediately waits for
scheduleEngine.registerNextTaskScheduleInstance
.
With many environments this becomes O(n) sequential I/O. Consider:await Promise.all( options.environments.map(async (environmentId) => { const instance = await this._prisma.taskScheduleInstance.create({ … }); await scheduleEngine.registerNextTaskScheduleInstance({ instanceId: instance.id }); }) );This keeps semantic order while cutting latency substantially.
206-218
: Typo & readability
instancesToDeleted
➜instancesToDelete
. Minor, but avoiding grammatical slips helps future readers.internal-packages/schedule-engine/src/engine/index.ts (1)
96-106
: Side-effects in constructor hinder testabilitySpawning the worker inside the constructor (
this.worker.start()
) means merely importing / instantiating the class connects to Redis and spawns threads, complicating unit tests and life-cycle management.
Expose an explicitstart()
method instead; call it from your singleton wrapper.apps/webapp/app/env.server.ts (1)
686-695
: Clarify overlapping concurrency env-varsThe trio
SCHEDULE_WORKER_CONCURRENCY_WORKERS
,
SCHEDULE_WORKER_CONCURRENCY_TASKS_PER_WORKER
, and
SCHEDULE_WORKER_CONCURRENCY_LIMIT
overlap but the codebase only readsconcurrency
(workers × tasks). Document which flags are authoritative or drop the unused ones to avoid misconfiguration.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
references/hello-world/src/trigger/schedule.ts
is excluded by!references/**
📒 Files selected for processing (49)
apps/webapp/app/env.server.ts
(1 hunks)apps/webapp/app/presenters/v3/NextRunListPresenter.server.ts
(2 hunks)apps/webapp/app/presenters/v3/RunListPresenter.server.ts
(2 hunks)apps/webapp/app/runEngine/services/batchTrigger.server.ts
(2 hunks)apps/webapp/app/runEngine/services/triggerTask.server.ts
(1 hunks)apps/webapp/app/services/email.server.ts
(2 hunks)apps/webapp/app/services/runsRepository.server.ts
(1 hunks)apps/webapp/app/services/worker.server.ts
(19 hunks)apps/webapp/app/v3/commonWorker.server.ts
(3 hunks)apps/webapp/app/v3/scheduleEngine.server.ts
(1 hunks)apps/webapp/app/v3/services/batchTriggerV3.server.ts
(3 hunks)apps/webapp/app/v3/services/cancelDevSessionRuns.server.ts
(2 hunks)apps/webapp/app/v3/services/cancelTaskAttemptDependencies.server.ts
(2 hunks)apps/webapp/app/v3/services/changeCurrentDeployment.server.ts
(1 hunks)apps/webapp/app/v3/services/createBackgroundWorker.server.ts
(3 hunks)apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV3.server.ts
(1 hunks)apps/webapp/app/v3/services/executeTasksWaitingForDeploy.ts
(2 hunks)apps/webapp/app/v3/services/registerNextTaskScheduleInstance.server.ts
(0 hunks)apps/webapp/app/v3/services/resumeBatchRun.server.ts
(2 hunks)apps/webapp/app/v3/services/resumeTaskDependency.server.ts
(2 hunks)apps/webapp/app/v3/services/resumeTaskRunDependencies.server.ts
(2 hunks)apps/webapp/app/v3/services/retryAttempt.server.ts
(2 hunks)apps/webapp/app/v3/services/timeoutDeployment.server.ts
(2 hunks)apps/webapp/app/v3/services/triggerScheduledTask.server.ts
(0 hunks)apps/webapp/app/v3/services/triggerTask.server.ts
(1 hunks)apps/webapp/app/v3/services/triggerTaskV1.server.ts
(2 hunks)apps/webapp/app/v3/services/upsertTaskSchedule.server.ts
(4 hunks)apps/webapp/app/v3/utils/distributedScheduling.server.ts
(1 hunks)apps/webapp/package.json
(1 hunks)apps/webapp/test/distributedScheduling.test.ts
(1 hunks)internal-packages/run-engine/src/engine/index.ts
(2 hunks)internal-packages/run-engine/src/engine/types.ts
(1 hunks)internal-packages/schedule-engine/README.md
(1 hunks)internal-packages/schedule-engine/package.json
(1 hunks)internal-packages/schedule-engine/src/engine/distributedScheduling.ts
(1 hunks)internal-packages/schedule-engine/src/engine/index.ts
(1 hunks)internal-packages/schedule-engine/src/engine/scheduleCalculation.ts
(1 hunks)internal-packages/schedule-engine/src/engine/types.ts
(1 hunks)internal-packages/schedule-engine/src/engine/workerCatalog.ts
(1 hunks)internal-packages/schedule-engine/src/index.ts
(1 hunks)internal-packages/schedule-engine/test/scheduleEngine.test.ts
(1 hunks)internal-packages/schedule-engine/test/setup.ts
(1 hunks)internal-packages/schedule-engine/tsconfig.build.json
(1 hunks)internal-packages/schedule-engine/tsconfig.json
(1 hunks)internal-packages/schedule-engine/tsconfig.src.json
(1 hunks)internal-packages/schedule-engine/tsconfig.test.json
(1 hunks)internal-packages/schedule-engine/vitest.config.ts
(1 hunks)packages/redis-worker/src/worker.ts
(1 hunks)packages/rsc/src/package.json
(1 hunks)
💤 Files with no reviewable changes (2)
- apps/webapp/app/v3/services/registerNextTaskScheduleInstance.server.ts
- apps/webapp/app/v3/services/triggerScheduledTask.server.ts
🧰 Additional context used
🧬 Code Graph Analysis (15)
apps/webapp/app/v3/services/changeCurrentDeployment.server.ts (1)
apps/webapp/app/v3/services/executeTasksWaitingForDeploy.ts (1)
ExecuteTasksWaitingForDeployService
(8-117)
apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV3.server.ts (1)
apps/webapp/app/v3/services/executeTasksWaitingForDeploy.ts (1)
ExecuteTasksWaitingForDeployService
(8-117)
apps/webapp/app/v3/services/resumeTaskRunDependencies.server.ts (1)
apps/webapp/app/v3/commonWorker.server.ts (1)
commonWorker
(279-279)
apps/webapp/app/services/email.server.ts (2)
apps/webapp/app/v3/commonWorker.server.ts (1)
commonWorker
(279-279)internal-packages/emails/src/index.tsx (1)
data
(80-122)
apps/webapp/app/v3/services/executeTasksWaitingForDeploy.ts (1)
apps/webapp/app/v3/commonWorker.server.ts (1)
commonWorker
(279-279)
apps/webapp/app/v3/services/timeoutDeployment.server.ts (3)
apps/webapp/app/v3/commonWorker.server.ts (1)
commonWorker
(279-279)apps/webapp/app/db.server.ts (1)
PrismaClientOrTransaction
(21-21)apps/webapp/app/services/worker.server.ts (1)
workerQueue
(373-373)
apps/webapp/app/v3/services/cancelTaskAttemptDependencies.server.ts (1)
apps/webapp/app/v3/commonWorker.server.ts (1)
commonWorker
(279-279)
packages/redis-worker/src/worker.ts (2)
internal-packages/schedule-engine/src/engine/index.ts (1)
JobHandlerParams
(217-225)internal-packages/zod-worker/src/index.ts (1)
K
(581-660)
apps/webapp/app/v3/services/retryAttempt.server.ts (1)
apps/webapp/app/v3/commonWorker.server.ts (1)
commonWorker
(279-279)
internal-packages/schedule-engine/src/engine/types.ts (4)
internal-packages/schedule-engine/src/index.ts (3)
TriggerScheduledTaskCallback
(5-5)ScheduleEngineOptions
(3-3)TriggerScheduleParams
(4-4)apps/webapp/app/db.server.ts (1)
PrismaClient
(228-228)internal-packages/redis/src/index.ts (1)
RedisOptions
(4-4)internal-packages/tracing/src/index.ts (2)
Tracer
(14-14)Meter
(16-16)
apps/webapp/app/v3/services/resumeTaskDependency.server.ts (1)
apps/webapp/app/v3/commonWorker.server.ts (1)
commonWorker
(279-279)
apps/webapp/test/distributedScheduling.test.ts (1)
apps/webapp/app/v3/utils/distributedScheduling.server.ts (1)
calculateDistributedExecutionTime
(6-31)
apps/webapp/app/v3/services/cancelDevSessionRuns.server.ts (2)
apps/webapp/app/v3/commonWorker.server.ts (1)
commonWorker
(279-279)apps/webapp/app/v3/services/batchTriggerV3.server.ts (1)
options
(894-900)
apps/webapp/app/v3/services/resumeBatchRun.server.ts (1)
apps/webapp/app/v3/commonWorker.server.ts (1)
commonWorker
(279-279)
apps/webapp/app/v3/services/createBackgroundWorker.server.ts (1)
apps/webapp/app/v3/scheduleEngine.server.ts (1)
scheduleEngine
(11-11)
🪛 LanguageTool
internal-packages/schedule-engine/README.md
[style] ~51-~51: ‘exactly the same’ might be wordy. Consider a shorter alternative.
Context: ...t all scheduled tasks from executing at exactly the same moment: ```typescript import { calcula...
(EN_WORDINESS_PREMIUM_EXACTLY_THE_SAME)
[uncategorized] ~101-~101: Loose punctuation mark.
Context: ...these configuration options: - prisma
: PrismaClient instance - redis
: Redis ...
(UNLIKELY_OPENING_PUNCTUATION)
⏰ Context from checks skipped due to timeout of 90000ms (25)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (10, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (9, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 10)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
- GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
- GitHub Check: typecheck / typecheck
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (16)
packages/rsc/src/package.json (1)
1-3
: Minimalpackage.json
LGTM, but double-check directory purposeDeclaring
"type": "module"
is fine and consistent with the rest of the repo.
Make sure:
- No other
package.json
higher in thepackages/rsc
tree overrides this.- Tooling that consumes this folder (ts-node, vitest, etc.) expects ESM.
If both are already covered, nothing else to do here.
apps/webapp/package.json (1)
53-57
: Workspace dependency added – ensure pipeline & lockfile are updated
"@internal/schedule-engine": "workspace:*"
looks correct.
Please run the package-manager install (pnpm install
/npm install -w
) and commit the updated lockfile so CI picks it up.apps/webapp/app/v3/services/changeCurrentDeployment.server.ts (1)
87-87
: Call site now matches newenqueue
signature – all good
ExecuteTasksWaitingForDeployService.enqueue
now only accepts(backgroundWorkerId, runAt?)
.
This update removes the stale Prisma argument and compiles cleanly.apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV3.server.ts (1)
164-166
: LGTM – signature change reflected correctly
ExecuteTasksWaitingForDeployService.enqueue
no longer requires the Prisma client, and the call site has been updated accordingly.apps/webapp/app/v3/services/createBackgroundWorker.server.ts (1)
571-573
: Error propagation unchanged but worth revisiting
scheduleEngine.registerNextTaskScheduleInstance
is awaited inside this tight loop.
If that call throws (e.g. transient Redis issue) the entire worker-creation flow aborts and rolls back the DB transaction – the same behaviour the removed service had, but now the failure surface is broader (Redis, distributed locks…).Consider wrapping in a retry helper or catching and logging non-fatal errors to avoid making deployments brittle.
Also applies to: 603-604
internal-packages/schedule-engine/vitest.config.ts (1)
11-13
: Confirm the esbuild target is aligned with runtime
target: "node18"
is fine today, but if the runtime matrix includes Node 20 (current LTS) the emitted code will miss out on native improvements (e.g., fetch, structuredClone). Worth double-checking the production containers.internal-packages/schedule-engine/src/index.ts (1)
1-6
: Public entry-point looks goodThe minimalist barrel file is clear and follows the Node16/ESM convention that the compiler will emit
.js
files, so the explicit.js
extension is appropriate. No further concerns.apps/webapp/app/v3/services/resumeTaskRunDependencies.server.ts (1)
8-9
: Import change looks correctSwitching to the new
commonWorker
aligns with the broader refactor.apps/webapp/app/services/email.server.ts (1)
7-8
: Import update acknowledgedMigrating to
commonWorker
is consistent with the rest of the PR.internal-packages/schedule-engine/package.json (1)
8-14
: Non-standard export key
"@triggerdotdev/source"
insideexports
isn’t a recognised condition and may break resolution in Node ≥16. Verify that tools relying on this key actually support it; otherwise use a documented condition such as"source"
or"development"
.apps/webapp/app/v3/commonWorker.server.ts (1)
188-195
: Ensure numeric env values
pollIntervalMs
,immediatePollIntervalMs
, worker counts, etc., are passed straight fromenv.*
. Confirm the Zod schema parses them to numbers; if they are still strings, RedisWorker will treat"5000"
as a string and mis-handle arithmetic/timeouts.If parsing isn’t already done in
env.server.ts
, coerce here:pollIntervalMs: Number(env.COMMON_WORKER_POLL_INTERVAL),apps/webapp/app/services/worker.server.ts (1)
238-246
: ConfirmfinalAttempt
semantics against worker implementation
finalAttempt
is derived fromjob.attempts === job.max_attempts
.
Ingraphile-worker
theattempts
counter already includes the current attempt, so the flag will betrue
while the job is still running, not after it has finally failed.
IfscheduleEngine.triggerScheduledTask()
internally interpretsfinalAttempt
as “no more retries will follow”, this could lead to premature deletion / alerting.await scheduleEngine.triggerScheduledTask({ instanceId: payload.instanceId, finalAttempt: job.attempts === job.max_attempts, // ← verify semantics });Please double-check the contract and adjust to
job.attempts + 1 === job.max_attempts
(or similar) if the engine expects the next attempt to be the last.apps/webapp/app/v3/services/timeoutDeployment.server.ts (1)
66-69
: Acknowledge both queues symmetrically
dequeue
is invoked onworkerQueue
, whileack
is invoked oncommonWorker
.
IfworkerQueue.dequeue()
fails (e.g., job not found) thecommonWorker.ack()
will still run, silently discarding the job in the new queue. Consider guarding with an existence check or catching errors to keep behaviour predictable during the migration window.packages/redis-worker/src/worker.ts (1)
37-48
: Type extraction looks goodExtracting
JobHandlerParams
makes handler definitions clearer and reusable; compile-time inference also improves.apps/webapp/app/v3/services/resumeBatchRun.server.ts (1)
337-344
: VerifyavailableAt
semantics
commonWorker.enqueue
often expects a Unix epoch (ms) whereas you’re passing aDate | undefined
.
Double-check the worker’s API – if it expects a number, wrap with.getTime()
; if it acceptsDate
, ignore this note.internal-packages/schedule-engine/src/engine/scheduleCalculation.ts (1)
22-30
: LGTM – cron calculation is concise and correct
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.
Actionable comments posted: 0
🧹 Nitpick comments (3)
apps/webapp/app/v3/commonWorker.server.ts (3)
127-154
: Two almost-identical job definitions may lead to accidental drift
"v3.processBatchTaskRun"
and"runengine.processBatchTaskRun"
repeat the same schema/timeout/retry logic, differing only by a couple of optional fields.
If both names are required, consider:
- Creating a shared
BatchTaskRunSchema
and spreading it into both entries to avoid silent divergence later.- Verifying that downstream producers/consumers consistently pick the intended key – the similarity makes copy-paste mistakes easy.
Let me know if you’d like a quick refactor snippet.
42-49
:DeliverEmailSchema
is imported but never reused in the handlerThe catalog entry validates against
DeliverEmailSchema
, yet the handler receivespayload
untyped (any
).
Annotating the handler parameter tightens compile-time safety:-import { DeliverEmailSchema } from "emails"; +import { DeliverEmailSchema, type DeliverEmail } from "emails"; … - scheduleEmail: async ({ payload }) => { - await sendEmail(payload); + scheduleEmail: async ({ payload }) => { + const email: DeliverEmail = payload; // satisfies schema + await sendEmail(email); },This prevents accidental misuse of the
payload
object.Also applies to: 211-214
78-87
: Constant-ify the ubiquitousvisibilityTimeoutMs: 60_000
/maxAttempts
The same magic numbers reappear in every catalog entry. Extracting small helpers (e.g.
const ONE_MINUTE = 60_000
) or a factory function improves readability and makes global tuning trivial.Also applies to: 112-114, 136-138, 150-154
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/webapp/app/v3/commonWorker.server.ts
(3 hunks)packages/redis-worker/src/queue.ts
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- packages/redis-worker/src/queue.ts
⏰ Context from checks skipped due to timeout of 90000ms (25)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
- GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (9, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (10, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 10)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
- GitHub Check: typecheck / typecheck
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
apps/webapp/app/v3/commonWorker.server.ts (1)
201-205
:❌ Incorrect review comment
Convert concurrency env values to numbers before passing to the worker
env
variables arestring | undefined
.RedisWorker
’sconcurrency
options expect numbers; handing it strings risks implicit coercion bugs when the library does arithmetic (e.g.Math.min
). Parse once at the boundary:- concurrency: { - workers: env.COMMON_WORKER_CONCURRENCY_WORKERS, - tasksPerWorker: env.COMMON_WORKER_CONCURRENCY_TASKS_PER_WORKER, - limit: env.COMMON_WORKER_CONCURRENCY_LIMIT, - }, + concurrency: { + workers: Number(env.COMMON_WORKER_CONCURRENCY_WORKERS), + tasksPerWorker: Number(env.COMMON_WORKER_CONCURRENCY_TASKS_PER_WORKER), + limit: Number(env.COMMON_WORKER_CONCURRENCY_LIMIT), + },
🏁 Script executed:
#!/bin/bash set -e echo "🔍 Searching for concurrency env vars in schema:" rg -n "COMMON_WORKER_CONCURRENCY_WORKERS" -n . echo "🔍 Locating where `env` is exported:" rg -n "export const env" -n .Length of output: 2457
🏁 Script executed:
#!/bin/bash set -e echo "🔍 Checking tasksPerWorker schema definition:" rg -n "COMMON_WORKER_CONCURRENCY_TASKS_PER_WORKER" apps/webapp/app/env.server.ts echo "🔍 Checking limit schema definition:" rg -n "COMMON_WORKER_CONCURRENCY_LIMIT" apps/webapp/app/env.server.tsLength of output: 507
🏁 Script executed:
#!/bin/bash set -e echo "🔍 Showing import statements in commonWorker.server.ts:" sed -n '1,50p' apps/webapp/app/v3/commonWorker.server.ts | grep -E "^import .*env"Length of output: 248
No conversion needed: concurrency env vars are already numbers
Theenv
import comes fromEnvironmentSchema.parse(process.env)
, where these keys usez.coerce.number().int().default(...)
. That guaranteesenv.COMMON_WORKER_CONCURRENCY_*
are typed and parsed asnumber
, so wrapping them inNumber(…)
is redundant.No changes required.
Likely an incorrect or invalid review comment.
…ter that out in the lists
68375fc
to
42c3f51
Compare
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.
Actionable comments posted: 1
♻️ Duplicate comments (2)
internal-packages/schedule-engine/src/engine/index.ts (2)
42-42
: Unsafe tracer fallback still present
CastingstartSpan
toany
to extract.tracer
defeats type-safety and risks breaking when the tracing util changes. Provide the tracer viaoptions.tracer
or an explicitgetTracer()
helper instead.
608-609
: Job-ID collision risk remains
id: \
scheduled-task-instance:${instanceId}`` is reused for every run; pending or stalled jobs with the same ID will cause enqueue failures or silent overwrites.
Include a unique component (timestamp or counter) in the ID.
🧹 Nitpick comments (2)
internal-packages/schedule-engine/src/engine/index.ts (1)
90-90
: Hard-coded “debug” logger level for worker
The worker always uses a newLogger("ScheduleEngineWorker", "debug")
, ignoring the engine’s configured log level.
Pass the chosen level (or the existing logger instance) to avoid noisy logs in production.internal-packages/schedule-engine/README.md (1)
51-57
: Minor wording nitpick
“executing at exactly the same moment” → “executing simultaneously” is shorter and clearer.🧰 Tools
🪛 LanguageTool
[style] ~51-~51: ‘exactly the same’ might be wordy. Consider a shorter alternative.
Context: ...t all scheduled tasks from executing at exactly the same moment: ```typescript import { calcula...(EN_WORDINESS_PREMIUM_EXACTLY_THE_SAME)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
references/hello-world/src/trigger/schedule.ts
is excluded by!references/**
📒 Files selected for processing (50)
apps/webapp/app/env.server.ts
(1 hunks)apps/webapp/app/presenters/v3/NextRunListPresenter.server.ts
(2 hunks)apps/webapp/app/presenters/v3/RunListPresenter.server.ts
(2 hunks)apps/webapp/app/runEngine/services/batchTrigger.server.ts
(2 hunks)apps/webapp/app/runEngine/services/triggerTask.server.ts
(1 hunks)apps/webapp/app/services/email.server.ts
(2 hunks)apps/webapp/app/services/runsRepository.server.ts
(1 hunks)apps/webapp/app/services/worker.server.ts
(19 hunks)apps/webapp/app/v3/commonWorker.server.ts
(3 hunks)apps/webapp/app/v3/scheduleEngine.server.ts
(1 hunks)apps/webapp/app/v3/services/batchTriggerV3.server.ts
(3 hunks)apps/webapp/app/v3/services/cancelDevSessionRuns.server.ts
(2 hunks)apps/webapp/app/v3/services/cancelTaskAttemptDependencies.server.ts
(2 hunks)apps/webapp/app/v3/services/changeCurrentDeployment.server.ts
(1 hunks)apps/webapp/app/v3/services/createBackgroundWorker.server.ts
(3 hunks)apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV3.server.ts
(1 hunks)apps/webapp/app/v3/services/executeTasksWaitingForDeploy.ts
(2 hunks)apps/webapp/app/v3/services/registerNextTaskScheduleInstance.server.ts
(0 hunks)apps/webapp/app/v3/services/resumeBatchRun.server.ts
(2 hunks)apps/webapp/app/v3/services/resumeTaskDependency.server.ts
(2 hunks)apps/webapp/app/v3/services/resumeTaskRunDependencies.server.ts
(2 hunks)apps/webapp/app/v3/services/retryAttempt.server.ts
(2 hunks)apps/webapp/app/v3/services/timeoutDeployment.server.ts
(2 hunks)apps/webapp/app/v3/services/triggerScheduledTask.server.ts
(0 hunks)apps/webapp/app/v3/services/triggerTask.server.ts
(1 hunks)apps/webapp/app/v3/services/triggerTaskV1.server.ts
(2 hunks)apps/webapp/app/v3/services/upsertTaskSchedule.server.ts
(4 hunks)apps/webapp/app/v3/utils/distributedScheduling.server.ts
(1 hunks)apps/webapp/package.json
(1 hunks)apps/webapp/test/distributedScheduling.test.ts
(1 hunks)internal-packages/run-engine/src/engine/index.ts
(2 hunks)internal-packages/run-engine/src/engine/types.ts
(1 hunks)internal-packages/schedule-engine/README.md
(1 hunks)internal-packages/schedule-engine/package.json
(1 hunks)internal-packages/schedule-engine/src/engine/distributedScheduling.ts
(1 hunks)internal-packages/schedule-engine/src/engine/index.ts
(1 hunks)internal-packages/schedule-engine/src/engine/scheduleCalculation.ts
(1 hunks)internal-packages/schedule-engine/src/engine/types.ts
(1 hunks)internal-packages/schedule-engine/src/engine/workerCatalog.ts
(1 hunks)internal-packages/schedule-engine/src/index.ts
(1 hunks)internal-packages/schedule-engine/test/scheduleEngine.test.ts
(1 hunks)internal-packages/schedule-engine/test/setup.ts
(1 hunks)internal-packages/schedule-engine/tsconfig.build.json
(1 hunks)internal-packages/schedule-engine/tsconfig.json
(1 hunks)internal-packages/schedule-engine/tsconfig.src.json
(1 hunks)internal-packages/schedule-engine/tsconfig.test.json
(1 hunks)internal-packages/schedule-engine/vitest.config.ts
(1 hunks)packages/redis-worker/src/queue.ts
(1 hunks)packages/redis-worker/src/worker.ts
(1 hunks)packages/rsc/src/package.json
(1 hunks)
💤 Files with no reviewable changes (2)
- apps/webapp/app/v3/services/registerNextTaskScheduleInstance.server.ts
- apps/webapp/app/v3/services/triggerScheduledTask.server.ts
✅ Files skipped from review due to trivial changes (2)
- internal-packages/schedule-engine/src/index.ts
- internal-packages/schedule-engine/src/engine/scheduleCalculation.ts
🚧 Files skipped from review as they are similar to previous changes (44)
- packages/rsc/src/package.json
- internal-packages/run-engine/src/engine/types.ts
- internal-packages/schedule-engine/test/setup.ts
- apps/webapp/package.json
- apps/webapp/app/v3/services/changeCurrentDeployment.server.ts
- internal-packages/schedule-engine/tsconfig.json
- apps/webapp/app/v3/services/createBackgroundWorker.server.ts
- apps/webapp/app/v3/services/triggerTask.server.ts
- apps/webapp/app/v3/services/createDeploymentBackgroundWorkerV3.server.ts
- packages/redis-worker/src/queue.ts
- apps/webapp/app/runEngine/services/triggerTask.server.ts
- internal-packages/schedule-engine/vitest.config.ts
- apps/webapp/app/services/runsRepository.server.ts
- internal-packages/schedule-engine/tsconfig.src.json
- apps/webapp/app/presenters/v3/NextRunListPresenter.server.ts
- internal-packages/schedule-engine/tsconfig.build.json
- apps/webapp/app/v3/services/resumeTaskRunDependencies.server.ts
- apps/webapp/app/services/email.server.ts
- internal-packages/schedule-engine/tsconfig.test.json
- apps/webapp/app/v3/services/triggerTaskV1.server.ts
- apps/webapp/app/v3/utils/distributedScheduling.server.ts
- apps/webapp/app/services/worker.server.ts
- apps/webapp/app/presenters/v3/RunListPresenter.server.ts
- apps/webapp/app/v3/services/cancelTaskAttemptDependencies.server.ts
- apps/webapp/app/v3/services/timeoutDeployment.server.ts
- internal-packages/schedule-engine/src/engine/workerCatalog.ts
- internal-packages/schedule-engine/package.json
- internal-packages/run-engine/src/engine/index.ts
- internal-packages/schedule-engine/src/engine/distributedScheduling.ts
- apps/webapp/app/runEngine/services/batchTrigger.server.ts
- apps/webapp/app/v3/services/resumeTaskDependency.server.ts
- apps/webapp/app/v3/commonWorker.server.ts
- apps/webapp/app/v3/services/cancelDevSessionRuns.server.ts
- apps/webapp/test/distributedScheduling.test.ts
- apps/webapp/app/v3/services/retryAttempt.server.ts
- packages/redis-worker/src/worker.ts
- apps/webapp/app/v3/services/resumeBatchRun.server.ts
- internal-packages/schedule-engine/test/scheduleEngine.test.ts
- apps/webapp/app/v3/services/executeTasksWaitingForDeploy.ts
- internal-packages/schedule-engine/src/engine/types.ts
- apps/webapp/app/v3/scheduleEngine.server.ts
- apps/webapp/app/v3/services/batchTriggerV3.server.ts
- apps/webapp/app/v3/services/upsertTaskSchedule.server.ts
- apps/webapp/app/env.server.ts
🧰 Additional context used
🪛 LanguageTool
internal-packages/schedule-engine/README.md
[style] ~51-~51: ‘exactly the same’ might be wordy. Consider a shorter alternative.
Context: ...t all scheduled tasks from executing at exactly the same moment: ```typescript import { calcula...
(EN_WORDINESS_PREMIUM_EXACTLY_THE_SAME)
[uncategorized] ~101-~101: Loose punctuation mark.
Context: ...these configuration options: - prisma
: PrismaClient instance - redis
: Redis ...
(UNLIKELY_OPENING_PUNCTUATION)
⏰ Context from checks skipped due to timeout of 90000ms (25)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (10, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (9, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 10)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
- GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
- GitHub Check: typecheck / typecheck
- GitHub Check: Analyze (javascript-typescript)
…ty (indexing now happens during the build image process)
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.
Actionable comments posted: 1
🔭 Outside diff range comments (3)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx (2)
52-55
: Remove the staledeploymentIndexingIsRetryable
importThe retry-indexing UI and worker flow were removed, yet the helper is still imported.
Keeping it around adds dead code and a silent dependency that will be forgotten later.-import { deploymentIndexingIsRetryable } from "~/v3/deploymentStatus";
328-343
:canRetryIndexing
is now pointless and causes an empty pop-over
canRetryIndexing
is still calculated but no longer drives any menu item.
When it istrue
(andcanBeMadeCurrent
isfalse
) we render the 3-dot menu with no entries, producing a confusing blank pop-over for users.Proposed minimal cleanup:
- const canRetryIndexing = deployment.isLatest && deploymentIndexingIsRetryable(deployment); const canBeRolledBack = canBeMadeCurrent && currentDeployment?.version && compareDeploymentVersions(deployment.version, currentDeployment.version) === -1; const canBePromoted = canBeMadeCurrent && !canBeRolledBack; - if (!canBeMadeCurrent && !canRetryIndexing) { + if (!canBeMadeCurrent) { return ( <TableCell to={path} isSelected={isSelected}> {""} </TableCell> ); }…and delete the now-unused
canRetryIndexing
computation (together with the import noted above).This avoids the UX glitch and eliminates redundant logic.
apps/webapp/app/v3/services/cancelTaskRunV1.server.ts (1)
114-121
: Enqueue dependency-cancellation jobs in parallel to improve latency.Inside a tight loop we
await
eachCancelTaskAttemptDependenciesService.enqueue
, forcing N sequential round-trips to Redis:for (const attempt of attempts) { await CancelTaskAttemptDependenciesService.enqueue(attempt.id); }This can be cut from O(N) network RTTs to ~1 by batching with
Promise.all
:- for (const attempt of attempts) { - await CancelTaskAttemptDependenciesService.enqueue(attempt.id); - } + await Promise.all( + attempts.map((a) => + CancelTaskAttemptDependenciesService.enqueue(a.id) + ), + );Throughput is higher and the surrounding cancellation flow finishes sooner.
♻️ Duplicate comments (2)
internal-packages/schedule-engine/src/engine/index.ts (2)
616-623
: Job-ID collision risk persists – ensure uniqueness
enqueue()
still uses onlyinstanceId
for the job ID; multiple runs queued before pruning will overwrite each other or be rejected.- id: `scheduled-task-instance:${instanceId}`, + // Include the exact schedule time to guarantee uniqueness + id: `scheduled-task-instance:${instanceId}:${exactScheduleTime.getTime()}`,
352-355
: Guard missing for optional dev-environment connectivity handler
isDevEnvironmentConnectedHandler
is invoked unconditionally and will throw if the option is omitted.- const [devConnectedError, isConnected] = await tryCatch( - this.options.isDevEnvironmentConnectedHandler(instance.environment.id) - ); + let isConnected = false; + let devConnectedError: unknown; + if (this.options.isDevEnvironmentConnectedHandler) { + [devConnectedError, isConnected] = await tryCatch( + this.options.isDevEnvironmentConnectedHandler(instance.environment.id) + ); + } else { + shouldTrigger = false; + skipReason = "dev_connection_handler_missing"; + }
🧹 Nitpick comments (4)
internal-packages/schedule-engine/src/engine/index.ts (3)
130-139
: PreferfindUnique
overfindFirst
for primary-key lookups
id
is a unique/PK column;findUnique
is faster, conveys intent, and avoids accidental surprises if the unique constraint changes.- const instance = await this.prisma.taskScheduleInstance.findFirst({ + const instance = await this.prisma.taskScheduleInstance.findUnique({ where: { id: params.instanceId }, include: { taskSchedule: true, environment: true, }, });Apply the same change in
triggerScheduledTask
.Also applies to: 259-273
159-166
: Usingnew Date()
whenlastScheduledTimestamp
is null can skip earlier executionsIf a schedule was created long ago but never run, defaulting to the current time may jump over intended back-dated runs. Consider seeding with the schedule’s creation time or the earliest valid cron match instead.
98-99
: Worker logger hard-codes"debug"
levelThis ignores
options.logLevel
supplied by the caller and causes inconsistent logging.- logger: new Logger("ScheduleEngineWorker", "debug"), + logger: new Logger("ScheduleEngineWorker", (this.options.logLevel ?? "info") as any),apps/webapp/app/v3/commonWorker.server.ts (1)
201-204
: Add defensive logging / metrics around email delivery.
sendEmail
may throw network-level errors (SMTP, SES throttling, etc.). Letting the exception propagate re-queues the job, but you lose the root-cause context. Wrap with try/catch to add structured logs (or increment a failure metric) before re-throwing:- scheduleEmail: async ({ payload }) => { - await sendEmail(payload); - }, + scheduleEmail: async ({ payload }) => { + try { + await sendEmail(payload); + } catch (err) { + logger.error("scheduleEmail failed", { payload, err }); + throw err; // preserve retry semantics + } + },This makes post-mortems faster without affecting job retries.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
apps/webapp/app/components/runs/v3/RetryDeploymentIndexingDialog.tsx
(0 hunks)apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments/route.tsx
(1 hunks)apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.retry-indexing.ts
(0 hunks)apps/webapp/app/services/worker.server.ts
(17 hunks)apps/webapp/app/v3/commonWorker.server.ts
(3 hunks)apps/webapp/app/v3/scheduleEngine.server.ts
(1 hunks)apps/webapp/app/v3/services/cancelTaskAttemptDependencies.server.ts
(2 hunks)apps/webapp/app/v3/services/cancelTaskRunV1.server.ts
(1 hunks)apps/webapp/app/v3/services/indexDeployment.server.ts
(0 hunks)apps/webapp/app/v3/services/resumeTaskRunDependencies.server.ts
(0 hunks)apps/webapp/app/v3/services/retryDeploymentIndexing.server.ts
(0 hunks)internal-packages/schedule-engine/src/engine/index.ts
(1 hunks)internal-packages/schedule-engine/src/engine/types.ts
(1 hunks)packages/redis-worker/src/worker.ts
(3 hunks)
💤 Files with no reviewable changes (5)
- apps/webapp/app/components/runs/v3/RetryDeploymentIndexingDialog.tsx
- apps/webapp/app/routes/resources.$projectId.deployments.$deploymentShortCode.retry-indexing.ts
- apps/webapp/app/v3/services/retryDeploymentIndexing.server.ts
- apps/webapp/app/v3/services/resumeTaskRunDependencies.server.ts
- apps/webapp/app/v3/services/indexDeployment.server.ts
🚧 Files skipped from review as they are similar to previous changes (5)
- apps/webapp/app/v3/services/cancelTaskAttemptDependencies.server.ts
- internal-packages/schedule-engine/src/engine/types.ts
- packages/redis-worker/src/worker.ts
- apps/webapp/app/services/worker.server.ts
- apps/webapp/app/v3/scheduleEngine.server.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
apps/webapp/app/v3/services/cancelTaskRunV1.server.ts (1)
apps/webapp/app/v3/services/cancelTaskAttemptDependencies.server.ts (1)
CancelTaskAttemptDependenciesService
(7-70)
apps/webapp/app/v3/commonWorker.server.ts (10)
internal-packages/emails/src/index.tsx (1)
DeliverEmailSchema
(20-32)apps/webapp/app/services/email.server.ts (1)
sendEmail
(104-106)apps/webapp/app/runEngine/services/batchTrigger.server.ts (2)
payload
(657-687)RunEngineBatchTriggerService
(52-688)apps/webapp/app/v3/services/batchTriggerV3.server.ts (2)
payload
(902-932)BatchTriggerV3Service
(95-933)apps/webapp/app/v3/services/resumeTaskDependency.server.ts (1)
ResumeTaskDependencyService
(8-172)apps/webapp/app/v3/services/timeoutDeployment.server.ts (1)
TimeoutDeploymentService
(8-70)apps/webapp/app/v3/services/executeTasksWaitingForDeploy.ts (1)
ExecuteTasksWaitingForDeployService
(8-117)apps/webapp/app/v3/services/retryAttempt.server.ts (1)
RetryAttemptService
(7-36)apps/webapp/app/v3/services/cancelTaskAttemptDependencies.server.ts (1)
CancelTaskAttemptDependenciesService
(7-70)apps/webapp/app/v3/services/cancelDevSessionRuns.server.ts (1)
CancelDevSessionRunsService
(18-107)
⏰ Context from checks skipped due to timeout of 90000ms (25)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (9, 10)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 10)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (10, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 10)
- GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
- 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 (2)
internal-packages/schedule-engine/src/engine/index.ts (1)
230-233
: Retry /finalAttempt
logic is a stub
finalAttempt
is alwaysfalse
; failures insidetriggerScheduledTask
will bubble and potentially spam retries without back-off. Verify the intended retry semantics and wire them up.apps/webapp/app/v3/commonWorker.server.ts (1)
191-195
: Ensure env numeric values are coerced to numbers.
@trigger.dev/redis-worker
expectsworkers
,tasksPerWorker
, andlimit
to be numbers.
Ifenv
surfaces raw strings, the worker will silently treat them asNaN
, effectively disabling the concurrency limits.- workers: env.COMMON_WORKER_CONCURRENCY_WORKERS, - tasksPerWorker: env.COMMON_WORKER_CONCURRENCY_TASKS_PER_WORKER, - limit: env.COMMON_WORKER_CONCURRENCY_LIMIT, + workers: Number(env.COMMON_WORKER_CONCURRENCY_WORKERS), + tasksPerWorker: Number(env.COMMON_WORKER_CONCURRENCY_TASKS_PER_WORKER), + limit: Number(env.COMMON_WORKER_CONCURRENCY_LIMIT),Confirm that the
env
helper already returns numbers; otherwise, coerce explicitly as above.
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.
Actionable comments posted: 1
♻️ Duplicate comments (2)
internal-packages/schedule-engine/src/engine/index.ts (2)
352-356
: Guard optionalisDevEnvironmentConnectedHandler
before invoking
this.options.isDevEnvironmentConnectedHandler
is still called unconditionally. If the option isn’t supplied, this throwsTypeError: undefined is not a function
, breaking triggers in development environments.
Add a presence check or make the handler mandatory.
616-622
: Job-ID collision risk remains
id: \
scheduled-task-instance:${instanceId}`is reused for every run. If a previous run hasn’t been pruned,
enqueue` may reject or overwrite, silently dropping executions.- id: `scheduled-task-instance:${instanceId}`, + id: `scheduled-task-instance:${instanceId}:${exactScheduleTime.getTime()}`,
🧹 Nitpick comments (1)
internal-packages/schedule-engine/src/engine/index.ts (1)
348-350
: High-cardinality metric label
dev_environment_checks_total
tags every sample withenvironment_id
, which can explode the cardinality of your time-series database.
Consider using low-cardinality labels (e.g.environment_type
) and exposing high-cardinality data via logs instead.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
internal-packages/schedule-engine/src/engine/index.ts
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (25)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (9, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (10, 10)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 10)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 10)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 10)
- GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
- GitHub Check: typecheck / typecheck
- GitHub Check: Analyze (javascript-typescript)
No description provided.