-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
feat: surface cron windows in webapp, cli, sdk #4572
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| --- | ||
| "@trigger.dev/core": patch | ||
| "@trigger.dev/sdk": patch | ||
| "trigger.dev": patch | ||
| --- | ||
|
|
||
| Define stable execution windows on declarative scheduled tasks. Schedule API responses now expose both the nominal CRON time and its assigned time, while deploy output and the dashboard show configured windows and upcoming assignments. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,11 @@ | ||
| import { type LoaderFunctionArgs, json } from "@remix-run/server-runtime"; | ||
| import { type GetDeploymentResponseBody } from "@trigger.dev/core/v3"; | ||
| import { BackgroundWorkerMetadata, type GetDeploymentResponseBody } from "@trigger.dev/core/v3"; | ||
| import { z } from "zod"; | ||
| import { prisma } from "~/db.server"; | ||
| import { authenticateApiKeyWithScope } from "~/services/apiAuth.server"; | ||
| import { logger } from "~/services/logger.server"; | ||
| import { env } from "~/env.server"; | ||
| import { calculateNextScheduleRunTimes, normalizeScheduleWindow } from "~/v3/scheduleWindow.server"; | ||
|
|
||
| const ParamsSchema = z.object({ | ||
| deploymentId: z.string(), | ||
|
|
@@ -53,6 +55,43 @@ export async function loader({ request, params }: LoaderFunctionArgs) { | |
| return json({ error: "Deployment not found" }, { status: 404 }); | ||
| } | ||
|
|
||
| const workerMetadata = deployment.worker | ||
| ? BackgroundWorkerMetadata.safeParse(deployment.worker.metadata) | ||
| : undefined; | ||
| const declarativeSchedules = workerMetadata?.success | ||
| ? workerMetadata.data.tasks.flatMap((task) => { | ||
| if ( | ||
| !task.schedule || | ||
| (task.schedule.environments && | ||
| !task.schedule.environments.includes(authenticatedEnv.type)) | ||
| ) { | ||
| return []; | ||
| } | ||
|
|
||
| const windowFields = normalizeScheduleWindow(task.schedule.window); | ||
| const [nextRun] = calculateNextScheduleRunTimes({ | ||
| cron: task.schedule.cron, | ||
| timezone: task.schedule.timezone, | ||
| deduplicationKey: task.id, | ||
| environmentId: authenticatedEnv.id, | ||
| schedulePhase: null, | ||
| phaseSecret: env.ENCRYPTION_KEY, | ||
| ...windowFields, | ||
| }); | ||
|
|
||
| return [ | ||
| { | ||
| task: task.id, | ||
| cron: task.schedule.cron, | ||
| timezone: task.schedule.timezone, | ||
| window: task.schedule.window, | ||
| nextRun: nextRun.nominalAt, | ||
| nextRunEffectiveAt: nextRun.effectiveAt, | ||
|
Comment on lines
+71
to
+89
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
ast-grep outline apps/webapp/app/v3/scheduleWindow.server.ts --items all
ast-grep outline apps/webapp/app/v3/services/createBackgroundWorker.server.ts --items all
ast-grep outline apps/webapp/app/routes/api.v1.deployments.\$deploymentId.ts --items all
rg -n -C 5 \
'deduplicationKey|schedulePhase|calculateNextScheduleRunTimes|registerNextTaskScheduleInstance' \
apps/webapp/app/v3/scheduleWindow.server.ts \
apps/webapp/app/v3/services/createBackgroundWorker.server.ts \
apps/webapp/app/routes/api.v1.deployments.\$deploymentId.ts \
internal-packages/database/prisma/schema.prismaRepository: triggerdotdev/trigger.dev Length of output: 16698 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- route ---'
cat -n 'apps/webapp/app/routes/api.v1.deployments.$deploymentId.ts' | sed -n '1,125p'
printf '%s\n' '--- declarative schedule sync ---'
cat -n apps/webapp/app/v3/services/createBackgroundWorker.server.ts | sed -n '643,780p'
printf '%s\n' '--- schedule models and creation/update paths ---'
rg -n -C 8 \
'model TaskSchedule|model TaskScheduleInstance|schedulePhase|deduplicationKey|TaskScheduleInstance' \
internal-packages/database/prisma/schema.prisma \
apps/webapp/app/v3 apps/webapp/app/services apps/webapp/app/models \
-g '*.ts' -g '*.tsx' -g '*.prisma'
printf '%s\n' '--- registration implementation ---'
rg -n -C 12 \
'registerNextTaskScheduleInstance|nextRunEffectiveAt|effectiveAt|nominalAt' \
apps/webapp/app/v3 -g '*.ts'Repository: triggerdotdev/trigger.dev Length of output: 50381 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- schedule engine registration ---'
rg -n -C 18 \
'registerNextTaskScheduleInstance|schedulePhase|deduplicationKey|calculateNextScheduleRunTimes|calculateEffectiveScheduleTime' \
apps/webapp/app/v3/scheduleEngine.server.ts \
apps/webapp/app/v3 -g '*.ts' \
| sed -n '1,260p'
printf '%s\n' '--- schedule-phase helpers and tests ---'
rg -n -C 12 \
'function calculateSchedulePhase|calculateSchedulePhase|calculateEffectiveScheduleTime|effectiveAt' \
apps packages internal-packages -g '*.ts' -g '*.tsx' -g '*.test.*' -g '*.spec.*' \
| sed -n '1,300p'
printf '%s\n' '--- exact declarative schedule lookup and route callers ---'
rg -n -C 10 \
'taskIdentifier.*task\.id|taskIdentifier.*taskIdentifier|environmentId.*authenticatedEnv|taskSchedule\.find|taskScheduleInstance\.find' \
apps/webapp/app -g '*.ts' -g '*.tsx' \
| sed -n '1,260p'Repository: triggerdotdev/trigger.dev Length of output: 50381 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- phase algorithm ---'
cat -n internal-packages/schedule-engine/src/engine/scheduleTiming.ts | sed -n '168,225p'
printf '%s\n' '--- registration definitions ---'
rg -l 'registerNextTaskScheduleInstance' . -g '*.ts' -g '*.tsx' | while read -r file; do
printf '%s\n' "--- $file"
rg -n -C 20 'registerNextTaskScheduleInstance' "$file" | sed -n '1,100p'
done
printf '%s\n' '--- declarative schedule tests ---'
rg -n -C 10 \
'syncDeclarativeSchedules|DECLARATIVE|nextRunEffectiveAt|schedulePhase' \
apps/webapp -g '*.test.*' -g '*.spec.*' -g '*.ts' \
| sed -n '1,260p'
printf '%s\n' '--- static invariant check ---'
python3 - <<'PY'
from pathlib import Path
route = Path("apps/webapp/app/routes/api.v1.deployments.$deploymentId.ts").read_text()
sync = Path("apps/webapp/app/v3/services/createBackgroundWorker.server.ts").read_text()
upsert = Path("apps/webapp/app/v3/services/upsertTaskSchedule.server.ts").read_text()
checks = {
"route uses task.id as deduplicationKey": "deduplicationKey: task.id" in route,
"route passes null schedulePhase": "schedulePhase: null" in route,
"declarative create omits deduplicationKey": "const newSchedule = await prisma.taskSchedule.create" in sync
and "deduplicationKey" not in sync[sync.index("const newSchedule = await prisma.taskSchedule.create"):
sync.index("const newSchedule = await prisma.taskSchedule.create") + 1800],
"declarative instance is registered": "registerNextTaskScheduleInstance({ instanceId: instance.id })" in sync,
"canonical API calculation uses persisted values": "deduplicationKey: taskSchedule.deduplicationKey" in upsert
and "schedulePhase: instance.schedulePhase" in upsert,
}
for name, result in checks.items():
print(f"{name}: {'PASS' if result else 'FAIL'}")
PYRepository: triggerdotdev/trigger.dev Length of output: 46376 Use the persisted schedule identity for The declarative schedule uses a generated |
||
| }, | ||
| ]; | ||
| }) | ||
| : []; | ||
|
|
||
| return json({ | ||
| id: deployment.friendlyId, | ||
| status: deployment.status, | ||
|
|
@@ -75,6 +114,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) { | |
| filePath: task.filePath, | ||
| exportName: task.exportName ?? "@deprecated", | ||
| })), | ||
| declarativeSchedules, | ||
| } | ||
| : undefined, | ||
| integrationDeployments: | ||
|
|
||
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.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Document imperative schedule windows.
Line 7 limits execution windows to declarative schedules. This PR also adds imperative schedule window support through the API. Include both paths in the package release note.
Proposed text
📝 Committable suggestion