Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 24557a7324 | |||
| 8b10a592f3 | |||
| d7089e12a9 | |||
| 162d864517 | |||
| 8ba9987944 | |||
| 7056ce53f2 |
@@ -167,6 +167,7 @@
|
||||
"tender-turkeys-compete",
|
||||
"thick-carrots-sneeze",
|
||||
"thin-parents-heal",
|
||||
"thirty-hotels-raise",
|
||||
"thirty-islands-kiss",
|
||||
"tidy-balloons-suffer",
|
||||
"tidy-dryers-sleep",
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
"@trigger.dev/core": patch
|
||||
---
|
||||
|
||||
Added declarative cron schedules
|
||||
@@ -1,6 +1,6 @@
|
||||
import { XMarkIcon } from "@heroicons/react/20/solid";
|
||||
import { useNavigate } from "@remix-run/react";
|
||||
import { RuntimeEnvironment } from "@trigger.dev/database";
|
||||
import { type RuntimeEnvironment } from "@trigger.dev/database";
|
||||
import { useCallback } from "react";
|
||||
import { z } from "zod";
|
||||
import { Input } from "~/components/primitives/Input";
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "../../primitives/SimpleSelect";
|
||||
import { ScheduleTypeCombo } from "./ScheduleType";
|
||||
|
||||
export const ScheduleListFilters = z.object({
|
||||
page: z.coerce.number().default(1),
|
||||
@@ -28,6 +29,7 @@ export const ScheduleListFilters = z.object({
|
||||
.string()
|
||||
.optional()
|
||||
.transform((value) => (value ? value.split(",") : undefined)),
|
||||
type: z.union([z.literal("declarative"), z.literal("imperative")]).optional(),
|
||||
search: z.string().optional(),
|
||||
});
|
||||
|
||||
@@ -48,7 +50,7 @@ export function ScheduleFilters({ possibleEnvironments, possibleTasks }: Schedul
|
||||
const navigate = useNavigate();
|
||||
const location = useOptimisticLocation();
|
||||
const searchParams = new URLSearchParams(location.search);
|
||||
const { environments, tasks, page, search } = ScheduleListFilters.parse(
|
||||
const { environments, tasks, page, search, type } = ScheduleListFilters.parse(
|
||||
Object.fromEntries(searchParams.entries())
|
||||
);
|
||||
|
||||
@@ -73,6 +75,10 @@ export function ScheduleFilters({ possibleEnvironments, possibleTasks }: Schedul
|
||||
handleFilterChange("environments", value === "ALL" ? undefined : value);
|
||||
}, []);
|
||||
|
||||
const handleTypeChange = useCallback((value: string | typeof All) => {
|
||||
handleFilterChange("type", value === "ALL" ? undefined : value);
|
||||
}, []);
|
||||
|
||||
const handleSearchChange = useThrottle((value: string) => {
|
||||
handleFilterChange("search", value.length === 0 ? undefined : value);
|
||||
}, 300);
|
||||
@@ -97,6 +103,30 @@ export function ScheduleFilters({ possibleEnvironments, possibleTasks }: Schedul
|
||||
defaultValue={search}
|
||||
onChange={(e) => handleSearchChange(e.target.value)}
|
||||
/>
|
||||
<SelectGroup>
|
||||
<Select name="type" value={type ?? "ALL"} onValueChange={handleTypeChange}>
|
||||
<SelectTrigger size="minimal" width="full">
|
||||
<SelectValue placeholder={"Select type"} className="ml-2 whitespace-nowrap p-0" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value={"ALL"}>
|
||||
<Paragraph
|
||||
variant="extra-small"
|
||||
className="whitespace-nowrap pl-0.5 transition group-hover:text-text-bright"
|
||||
>
|
||||
All types
|
||||
</Paragraph>
|
||||
</SelectItem>
|
||||
<SelectItem value={"declarative"}>
|
||||
<ScheduleTypeCombo type="DECLARATIVE" className="text-xs text-text-dimmed" />
|
||||
</SelectItem>
|
||||
<SelectItem value={"imperative"}>
|
||||
<ScheduleTypeCombo type="IMPERATIVE" className="text-xs text-text-dimmed" />
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</SelectGroup>
|
||||
|
||||
<SelectGroup>
|
||||
<Select
|
||||
name="environment"
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { ArchiveBoxIcon, ArrowsRightLeftIcon } from "@heroicons/react/20/solid";
|
||||
import type { ScheduleType } from "@trigger.dev/database";
|
||||
import { cn } from "~/utils/cn";
|
||||
|
||||
export function ScheduleTypeCombo({ type, className }: { type: ScheduleType; className?: string }) {
|
||||
return (
|
||||
<div className={cn("flex items-center space-x-1", className)}>
|
||||
<ScheduleTypeIcon type={type} />
|
||||
<span>{scheduleTypeName(type)}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function ScheduleTypeIcon({ type, className }: { type: ScheduleType; className?: string }) {
|
||||
switch (type) {
|
||||
case "IMPERATIVE":
|
||||
return <ArrowsRightLeftIcon className={cn("size-4", className)} />;
|
||||
case "DECLARATIVE":
|
||||
return <ArchiveBoxIcon className={cn("size-4", className)} />;
|
||||
}
|
||||
}
|
||||
export function scheduleTypeName(type: ScheduleType) {
|
||||
switch (type) {
|
||||
case "IMPERATIVE":
|
||||
return "Imperative";
|
||||
case "DECLARATIVE":
|
||||
return "Declarative";
|
||||
}
|
||||
}
|
||||
@@ -230,8 +230,12 @@ export function TaskRunsTable({
|
||||
formatDuration(new Date(run.createdAt), new Date(run.startedAt), {
|
||||
style: "short",
|
||||
})
|
||||
) : (
|
||||
) : run.isCancellable ? (
|
||||
<LiveTimer startTime={new Date(run.createdAt)} />
|
||||
) : (
|
||||
formatDuration(new Date(run.createdAt), new Date(run.updatedAt), {
|
||||
style: "short",
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
|
||||
@@ -25,7 +25,7 @@ export class ApiRunPresenter {
|
||||
}: ApiRunOptions) {
|
||||
const take = Math.min(maxTasks, 50);
|
||||
|
||||
return await prisma.jobRun.findUnique({
|
||||
return await prisma.jobRun.findFirst({
|
||||
where: {
|
||||
id: runId,
|
||||
},
|
||||
|
||||
@@ -88,6 +88,7 @@ export class EditSchedulePresenter {
|
||||
const schedule = await this.#prismaClient.taskSchedule.findFirst({
|
||||
select: {
|
||||
id: true,
|
||||
type: true,
|
||||
friendlyId: true,
|
||||
generatorExpression: true,
|
||||
externalId: true,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Prisma, RuntimeEnvironmentType } from "@trigger.dev/database";
|
||||
import { Prisma, RuntimeEnvironmentType, ScheduleType } from "@trigger.dev/database";
|
||||
import { ScheduleListFilters } from "~/components/runs/v3/ScheduleFilters";
|
||||
import { sqlDatabaseSchema } from "~/db.server";
|
||||
import { displayableEnvironment } from "~/models/runtimeEnvironment.server";
|
||||
@@ -16,6 +16,7 @@ const DEFAULT_PAGE_SIZE = 20;
|
||||
|
||||
export type ScheduleListItem = {
|
||||
id: string;
|
||||
type: ScheduleType;
|
||||
friendlyId: string;
|
||||
taskIdentifier: string;
|
||||
deduplicationKey: string | null;
|
||||
@@ -44,10 +45,17 @@ export class ScheduleListPresenter extends BasePresenter {
|
||||
environments,
|
||||
search,
|
||||
page,
|
||||
type,
|
||||
pageSize = DEFAULT_PAGE_SIZE,
|
||||
}: ScheduleListOptions) {
|
||||
const hasFilters =
|
||||
tasks !== undefined || environments !== undefined || (search !== undefined && search !== "");
|
||||
type !== undefined ||
|
||||
tasks !== undefined ||
|
||||
environments !== undefined ||
|
||||
(search !== undefined && search !== "");
|
||||
|
||||
const filterType =
|
||||
type === "declarative" ? "DECLARATIVE" : type === "imperative" ? "IMPERATIVE" : undefined;
|
||||
|
||||
// Find the project scoped to the organization
|
||||
const project = await this._replica.project.findFirstOrThrow({
|
||||
@@ -105,6 +113,7 @@ export class ScheduleListPresenter extends BasePresenter {
|
||||
environmentId: environments ? { in: environments } : undefined,
|
||||
},
|
||||
},
|
||||
type: filterType,
|
||||
AND: search
|
||||
? {
|
||||
OR: [
|
||||
@@ -141,6 +150,7 @@ export class ScheduleListPresenter extends BasePresenter {
|
||||
const rawSchedules = await this._replica.taskSchedule.findMany({
|
||||
select: {
|
||||
id: true,
|
||||
type: true,
|
||||
friendlyId: true,
|
||||
taskIdentifier: true,
|
||||
deduplicationKey: true,
|
||||
@@ -166,6 +176,7 @@ export class ScheduleListPresenter extends BasePresenter {
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
type: filterType,
|
||||
AND: search
|
||||
? {
|
||||
OR: [
|
||||
@@ -215,11 +226,12 @@ export class ScheduleListPresenter extends BasePresenter {
|
||||
ON t."scheduleId" = r."scheduleId" AND t."createdAt" = r."LatestRun";`
|
||||
: [];
|
||||
|
||||
const schedules = rawSchedules.map((schedule) => {
|
||||
const schedules: ScheduleListItem[] = rawSchedules.map((schedule) => {
|
||||
const latestRun = latestRuns.find((r) => r.scheduleId === schedule.id);
|
||||
|
||||
return {
|
||||
id: schedule.id,
|
||||
type: schedule.type,
|
||||
friendlyId: schedule.friendlyId,
|
||||
taskIdentifier: schedule.taskIdentifier,
|
||||
deduplicationKey: schedule.deduplicationKey,
|
||||
|
||||
@@ -21,6 +21,7 @@ export class ViewSchedulePresenter {
|
||||
const schedule = await this.#prismaClient.taskSchedule.findFirst({
|
||||
select: {
|
||||
id: true,
|
||||
type: true,
|
||||
friendlyId: true,
|
||||
generatorExpression: true,
|
||||
generatorDescription: true,
|
||||
@@ -99,6 +100,7 @@ export class ViewSchedulePresenter {
|
||||
public toJSONResponse(result: NonNullable<Awaited<ReturnType<ViewSchedulePresenter["call"]>>>) {
|
||||
const response: ScheduleObject = {
|
||||
id: result.schedule.friendlyId,
|
||||
type: result.schedule.type,
|
||||
task: result.schedule.taskIdentifier,
|
||||
active: result.schedule.active,
|
||||
nextRun: result.schedule.nextRuns[0],
|
||||
|
||||
@@ -12,7 +12,7 @@ const ParamsSchema = z.object({
|
||||
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
|
||||
const { organizationId } = ParamsSchema.parse(params);
|
||||
|
||||
const org = await prisma.organization.findUnique({
|
||||
const org = await prisma.organization.findFirst({
|
||||
select: {
|
||||
slug: true,
|
||||
_count: {
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ const ParamsSchema = z.object({
|
||||
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
|
||||
const { organizationId } = ParamsSchema.parse(params);
|
||||
|
||||
const org = await prisma.organization.findUnique({
|
||||
const org = await prisma.organization.findFirst({
|
||||
select: {
|
||||
slug: true,
|
||||
_count: {
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ const ParamsSchema = z.object({
|
||||
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
|
||||
const { organizationId } = ParamsSchema.parse(params);
|
||||
|
||||
const org = await prisma.organization.findUnique({
|
||||
const org = await prisma.organization.findFirst({
|
||||
select: {
|
||||
slug: true,
|
||||
_count: {
|
||||
|
||||
+104
-67
@@ -1,15 +1,21 @@
|
||||
import { parse } from "@conform-to/zod";
|
||||
import { BoltIcon, BoltSlashIcon, PencilSquareIcon, TrashIcon } from "@heroicons/react/20/solid";
|
||||
import {
|
||||
BoltIcon,
|
||||
BoltSlashIcon,
|
||||
BookOpenIcon,
|
||||
PencilSquareIcon,
|
||||
TrashIcon,
|
||||
} from "@heroicons/react/20/solid";
|
||||
import { DialogDescription } from "@radix-ui/react-dialog";
|
||||
import { Form, useLocation } from "@remix-run/react";
|
||||
import { ActionFunctionArgs, LoaderFunctionArgs, json } from "@remix-run/server-runtime";
|
||||
import { token } from "morgan";
|
||||
import { type ActionFunctionArgs, type LoaderFunctionArgs, json } from "@remix-run/server-runtime";
|
||||
import { typedjson, useTypedLoaderData } from "remix-typedjson";
|
||||
import { z } from "zod";
|
||||
import { ExitIcon } from "~/assets/icons/ExitIcon";
|
||||
import { InlineCode } from "~/components/code/InlineCode";
|
||||
import { EnvironmentLabel, EnvironmentLabels } from "~/components/environments/EnvironmentLabel";
|
||||
import { EnvironmentLabels } from "~/components/environments/EnvironmentLabel";
|
||||
import { Button, LinkButton } from "~/components/primitives/Buttons";
|
||||
import { Callout, variantClasses } from "~/components/primitives/Callout";
|
||||
import { DateTime } from "~/components/primitives/DateTime";
|
||||
import {
|
||||
Dialog,
|
||||
@@ -19,6 +25,7 @@ import {
|
||||
DialogTrigger,
|
||||
} from "~/components/primitives/Dialog";
|
||||
import { Header2, Header3 } from "~/components/primitives/Headers";
|
||||
import { InfoPanel } from "~/components/primitives/InfoPanel";
|
||||
import { Paragraph } from "~/components/primitives/Paragraph";
|
||||
import { Property, PropertyTable } from "~/components/primitives/PropertyTable";
|
||||
import {
|
||||
@@ -31,11 +38,11 @@ import {
|
||||
TableRow,
|
||||
} from "~/components/primitives/Table";
|
||||
import { EnabledStatus } from "~/components/runs/v3/EnabledStatus";
|
||||
import { ScheduleTypeCombo } from "~/components/runs/v3/ScheduleType";
|
||||
import { TaskRunsTable } from "~/components/runs/v3/TaskRunsTable";
|
||||
import { prisma } from "~/db.server";
|
||||
import { useOrganization } from "~/hooks/useOrganizations";
|
||||
import { useProject } from "~/hooks/useProject";
|
||||
import { useUser } from "~/hooks/useUser";
|
||||
import { redirectWithErrorMessage, redirectWithSuccessMessage } from "~/models/message.server";
|
||||
import { findProjectBySlug } from "~/models/project.server";
|
||||
import { ViewSchedulePresenter } from "~/presenters/v3/ViewSchedulePresenter.server";
|
||||
@@ -197,8 +204,15 @@ export default function Page() {
|
||||
|
||||
const isUtc = schedule.timezone === "UTC";
|
||||
|
||||
const isImperative = schedule.type === "IMPERATIVE";
|
||||
|
||||
return (
|
||||
<div className="grid h-full max-h-full grid-rows-[2.5rem_1fr_3.25rem] overflow-hidden bg-background-bright">
|
||||
<div
|
||||
className={cn(
|
||||
"grid h-full max-h-full overflow-hidden bg-background-bright",
|
||||
isImperative ? "grid-rows-[2.5rem_1fr_3.25rem]" : "grid-rows-[2.5rem_1fr]"
|
||||
)}
|
||||
>
|
||||
<div className="mx-3 flex items-center justify-between gap-2 border-b border-grid-dimmed">
|
||||
<Header2 className={cn("whitespace-nowrap")}>{schedule.friendlyId}</Header2>
|
||||
<LinkButton
|
||||
@@ -214,6 +228,9 @@ export default function Page() {
|
||||
<PropertyTable>
|
||||
<Property label="Schedule ID">{schedule.friendlyId}</Property>
|
||||
<Property label="Task ID">{schedule.taskIdentifier}</Property>
|
||||
<Property label="Type">
|
||||
<ScheduleTypeCombo type={schedule.type} className="text-sm" />
|
||||
</Property>
|
||||
<Property label="CRON (UTC)" labelClassName="self-start">
|
||||
<div className="space-y-2">
|
||||
<InlineCode variant="extra-small">{schedule.cron}</InlineCode>
|
||||
@@ -224,15 +241,19 @@ export default function Page() {
|
||||
<Property label="Environments">
|
||||
<EnvironmentLabels size="small" environments={schedule.environments} />
|
||||
</Property>
|
||||
<Property label="External ID">
|
||||
{schedule.externalId ? schedule.externalId : "–"}
|
||||
</Property>
|
||||
<Property label="Deduplication key">
|
||||
{schedule.userProvidedDeduplicationKey ? schedule.deduplicationKey : "–"}
|
||||
</Property>
|
||||
<Property label="Status">
|
||||
<EnabledStatus enabled={schedule.active} />
|
||||
</Property>
|
||||
{isImperative && (
|
||||
<>
|
||||
<Property label="External ID">
|
||||
{schedule.externalId ? schedule.externalId : "–"}
|
||||
</Property>
|
||||
<Property label="Deduplication key">
|
||||
{schedule.userProvidedDeduplicationKey ? schedule.deduplicationKey : "–"}
|
||||
</Property>
|
||||
<Property label="Status">
|
||||
<EnabledStatus enabled={schedule.active} />
|
||||
</Property>
|
||||
</>
|
||||
)}
|
||||
</PropertyTable>
|
||||
<div className="flex flex-col gap-1">
|
||||
<Header3>Last 5 runs</Header3>
|
||||
@@ -288,68 +309,84 @@ export default function Page() {
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
{!isImperative && (
|
||||
<InfoPanel
|
||||
title="Editing declarative schedules"
|
||||
icon={BookOpenIcon}
|
||||
iconClassName="text-indigo-500"
|
||||
variant="info"
|
||||
buttonLabel="Docs"
|
||||
to="https://trigger.dev/docs/v3/tasks-scheduled"
|
||||
panelClassName="max-w-full"
|
||||
>
|
||||
You can only edit a declarative schedule by updating your schedules.task and then
|
||||
running the CLI dev and deploy commands.
|
||||
</InfoPanel>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-2 border-t border-grid-dimmed px-2">
|
||||
<div className="flex items-center gap-4">
|
||||
<Form method="post">
|
||||
<Button
|
||||
type="submit"
|
||||
variant="minimal/medium"
|
||||
LeadingIcon={schedule.active ? BoltSlashIcon : BoltIcon}
|
||||
leadingIconClassName={schedule.active ? "text-dimmed" : "text-success"}
|
||||
name="action"
|
||||
value={schedule.active ? "disable" : "enable"}
|
||||
>
|
||||
{schedule.active ? "Disable" : "Enable"}
|
||||
</Button>
|
||||
</Form>
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
{isImperative && (
|
||||
<div className="flex items-center justify-between gap-2 border-t border-grid-dimmed px-2">
|
||||
<div className="flex items-center gap-4">
|
||||
<Form method="post">
|
||||
<Button
|
||||
type="submit"
|
||||
variant="minimal/medium"
|
||||
LeadingIcon={TrashIcon}
|
||||
leadingIconClassName="text-error"
|
||||
className="text-error"
|
||||
LeadingIcon={schedule.active ? BoltSlashIcon : BoltIcon}
|
||||
leadingIconClassName={schedule.active ? "text-dimmed" : "text-success"}
|
||||
name="action"
|
||||
value="delete"
|
||||
value={schedule.active ? "disable" : "enable"}
|
||||
>
|
||||
Delete
|
||||
{schedule.active ? "Disable" : "Enable"}
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>Delete schedule</DialogHeader>
|
||||
<DialogDescription>
|
||||
Are you sure you want to delete this schedule? This can't be reversed.
|
||||
</DialogDescription>
|
||||
<DialogFooter>
|
||||
<Form method="post">
|
||||
<Button
|
||||
type="submit"
|
||||
variant="danger/small"
|
||||
LeadingIcon={TrashIcon}
|
||||
name="action"
|
||||
value="delete"
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</Form>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</Form>
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="minimal/medium"
|
||||
LeadingIcon={TrashIcon}
|
||||
leadingIconClassName="text-error"
|
||||
className="text-error"
|
||||
name="action"
|
||||
value="delete"
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>Delete schedule</DialogHeader>
|
||||
<DialogDescription>
|
||||
Are you sure you want to delete this schedule? This can't be reversed.
|
||||
</DialogDescription>
|
||||
<DialogFooter>
|
||||
<Form method="post">
|
||||
<Button
|
||||
type="submit"
|
||||
variant="danger/small"
|
||||
LeadingIcon={TrashIcon}
|
||||
name="action"
|
||||
value="delete"
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
</Form>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<LinkButton
|
||||
variant="tertiary/medium"
|
||||
to={`${v3EditSchedulePath(organization, project, schedule)}${location.search}`}
|
||||
LeadingIcon={PencilSquareIcon}
|
||||
>
|
||||
Edit schedule
|
||||
</LinkButton>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-4">
|
||||
<LinkButton
|
||||
variant="tertiary/medium"
|
||||
to={`${v3EditSchedulePath(organization, project, schedule)}${location.search}`}
|
||||
LeadingIcon={PencilSquareIcon}
|
||||
>
|
||||
Edit schedule
|
||||
</LinkButton>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
+6
-2
@@ -1,8 +1,8 @@
|
||||
import { LoaderFunctionArgs } from "@remix-run/server-runtime";
|
||||
import { LoaderFunctionArgs, redirect } from "@remix-run/server-runtime";
|
||||
import { typedjson, useTypedLoaderData } from "remix-typedjson";
|
||||
import { EditSchedulePresenter } from "~/presenters/v3/EditSchedulePresenter.server";
|
||||
import { requireUserId } from "~/services/session.server";
|
||||
import { ProjectParamSchema, v3ScheduleParams } from "~/utils/pathBuilder";
|
||||
import { ProjectParamSchema, v3ScheduleParams, v3SchedulesPath } from "~/utils/pathBuilder";
|
||||
import { humanToCronSupported } from "~/v3/humanToCron.server";
|
||||
import { UpsertScheduleForm } from "../resources.orgs.$organizationSlug.projects.$projectParam.schedules.new/route";
|
||||
|
||||
@@ -17,6 +17,10 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
|
||||
friendlyId: scheduleParam,
|
||||
});
|
||||
|
||||
if (result.schedule?.type === "DECLARATIVE") {
|
||||
throw redirect(v3SchedulesPath({ slug: organizationSlug }, { slug: projectParam }));
|
||||
}
|
||||
|
||||
return typedjson({ ...result, showGenerateField: humanToCronSupported });
|
||||
};
|
||||
|
||||
|
||||
+68
-3
@@ -10,6 +10,11 @@ import { EnvironmentLabels } from "~/components/environments/EnvironmentLabel";
|
||||
import { MainCenteredContainer, PageBody, PageContainer } from "~/components/layout/AppLayout";
|
||||
import { Button, LinkButton } from "~/components/primitives/Buttons";
|
||||
import { DateTime } from "~/components/primitives/DateTime";
|
||||
import {
|
||||
ScheduleTypeCombo,
|
||||
ScheduleTypeIcon,
|
||||
scheduleTypeName,
|
||||
} from "~/components/runs/v3/ScheduleType";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -334,6 +339,51 @@ function SchedulesTable({
|
||||
<TableRow>
|
||||
<TableHeaderCell>ID</TableHeaderCell>
|
||||
<TableHeaderCell>Task ID</TableHeaderCell>
|
||||
<TableHeaderCell
|
||||
tooltip={
|
||||
<div className="flex max-w-xs flex-col gap-4 p-1">
|
||||
<div>
|
||||
<div className="mb-0.5 flex items-center gap-1.5 text-sm">
|
||||
<div className={"flex items-center space-x-1"}>
|
||||
<ScheduleTypeIcon type={"DECLARATIVE"} className="text-sky-500" />
|
||||
<span className="font-medium">{scheduleTypeName("DECLARATIVE")}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Paragraph variant="small" className="!text-wrap text-text-dimmed">
|
||||
Declarative schedules are defined in a{" "}
|
||||
<InlineCode variant="extra-small">schedules.task</InlineCode> with the{" "}
|
||||
<InlineCode variant="extra-small">cron</InlineCode>
|
||||
property. They sync when you update your{" "}
|
||||
<InlineCode variant="extra-small">schedules.task</InlineCode> definition and run
|
||||
the CLI dev or deploy commands.
|
||||
</Paragraph>
|
||||
</div>
|
||||
<div>
|
||||
<div className="mb-0.5 flex items-center gap-1.5 text-sm">
|
||||
<div className={"flex items-center space-x-1"}>
|
||||
<ScheduleTypeIcon type={"IMPERATIVE"} className="text-teal-500" />
|
||||
<span className="font-medium">{scheduleTypeName("IMPERATIVE")}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Paragraph variant="small" className="!text-wrap text-text-dimmed">
|
||||
Imperative schedules are defined here in the dashboard or by using the SDK
|
||||
functions to create or delete them. They can be created, updated, disabled, and
|
||||
deleted from the dashboard or using the SDK.
|
||||
</Paragraph>
|
||||
</div>
|
||||
<div>
|
||||
<LinkButton
|
||||
variant="tertiary/medium"
|
||||
to="https://trigger.dev/docs/v3/tasks-scheduled"
|
||||
>
|
||||
View the docs
|
||||
</LinkButton>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
Type
|
||||
</TableHeaderCell>
|
||||
<TableHeaderCell>External ID</TableHeaderCell>
|
||||
<TableHeaderCell>CRON</TableHeaderCell>
|
||||
<TableHeaderCell hiddenLabel>CRON description</TableHeaderCell>
|
||||
@@ -362,7 +412,14 @@ function SchedulesTable({
|
||||
{schedule.taskIdentifier}
|
||||
</TableCell>
|
||||
<TableCell to={path} className={cellClass}>
|
||||
{schedule.externalId ? schedule.externalId : "–"}
|
||||
<ScheduleTypeCombo type={schedule.type} />
|
||||
</TableCell>
|
||||
<TableCell to={path} className={cellClass}>
|
||||
{schedule.type === "IMPERATIVE"
|
||||
? schedule.externalId
|
||||
? schedule.externalId
|
||||
: "–"
|
||||
: "N/A"}
|
||||
</TableCell>
|
||||
<TableCell to={path} className={cellClass}>
|
||||
{schedule.cron}
|
||||
@@ -384,13 +441,21 @@ function SchedulesTable({
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell to={path} className={cellClass}>
|
||||
{schedule.userProvidedDeduplicationKey ? schedule.deduplicationKey : "–"}
|
||||
{schedule.type === "IMPERATIVE"
|
||||
? schedule.userProvidedDeduplicationKey
|
||||
? schedule.deduplicationKey
|
||||
: "–"
|
||||
: "N/A"}
|
||||
</TableCell>
|
||||
<TableCell to={path} className={cellClass}>
|
||||
<EnvironmentLabels environments={schedule.environments} size="small" />
|
||||
</TableCell>
|
||||
<TableCell to={path}>
|
||||
<EnabledStatus enabled={schedule.active} />
|
||||
{schedule.type === "IMPERATIVE" ? (
|
||||
<EnabledStatus enabled={schedule.active} />
|
||||
) : (
|
||||
"N/A"
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
|
||||
@@ -34,7 +34,7 @@ export async function loader({ params, request }: LoaderFunctionArgs) {
|
||||
const userId = await requireUserId(request);
|
||||
const { organizationSlug } = OrganizationParamsSchema.parse(params);
|
||||
|
||||
const organization = await prisma.organization.findUnique({
|
||||
const organization = await prisma.organization.findFirst({
|
||||
where: { slug: organizationSlug, members: { some: { userId } } },
|
||||
select: {
|
||||
id: true,
|
||||
|
||||
@@ -3,7 +3,11 @@ import { CreateBackgroundWorkerRequestBody } from "@trigger.dev/core/v3";
|
||||
import { z } from "zod";
|
||||
import { authenticateApiRequest } from "~/services/apiAuth.server";
|
||||
import { logger } from "~/services/logger.server";
|
||||
import { CreateBackgroundWorkerService } from "~/v3/services/createBackgroundWorker.server";
|
||||
import { ServiceValidationError } from "~/v3/services/baseService.server";
|
||||
import {
|
||||
CreateBackgroundWorkerService,
|
||||
CreateDeclarativeScheduleError,
|
||||
} from "~/v3/services/createBackgroundWorker.server";
|
||||
|
||||
const ParamsSchema = z.object({
|
||||
projectRef: z.string(),
|
||||
@@ -42,14 +46,26 @@ export async function action({ request, params }: ActionFunctionArgs) {
|
||||
|
||||
const service = new CreateBackgroundWorkerService();
|
||||
|
||||
const backgroundWorker = await service.call(projectRef, authenticatedEnv, body.data);
|
||||
try {
|
||||
const backgroundWorker = await service.call(projectRef, authenticatedEnv, body.data);
|
||||
|
||||
return json(
|
||||
{
|
||||
id: backgroundWorker.friendlyId,
|
||||
version: backgroundWorker.version,
|
||||
contentHash: backgroundWorker.contentHash,
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
return json(
|
||||
{
|
||||
id: backgroundWorker.friendlyId,
|
||||
version: backgroundWorker.version,
|
||||
contentHash: backgroundWorker.contentHash,
|
||||
},
|
||||
{ status: 200 }
|
||||
);
|
||||
} catch (e) {
|
||||
logger.error("Failed to create background worker", { error: e });
|
||||
|
||||
if (e instanceof ServiceValidationError) {
|
||||
return json({ error: e.message }, { status: 400 });
|
||||
} else if (e instanceof CreateDeclarativeScheduleError) {
|
||||
return json({ error: e.message }, { status: 400 });
|
||||
}
|
||||
|
||||
return json({ error: "Failed to create background worker" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ export async function action({ request, params }: ActionFunctionArgs) {
|
||||
|
||||
const responseObject: ScheduleObject = {
|
||||
id: schedule.id,
|
||||
type: schedule.type,
|
||||
task: schedule.task,
|
||||
active: schedule.active,
|
||||
generator: {
|
||||
|
||||
@@ -50,6 +50,7 @@ export async function action({ request }: ActionFunctionArgs) {
|
||||
|
||||
const responseObject: ScheduleObject = {
|
||||
id: schedule.id,
|
||||
type: schedule.type,
|
||||
task: schedule.task,
|
||||
active: schedule.active,
|
||||
generator: {
|
||||
@@ -107,6 +108,7 @@ export async function loader({ request }: LoaderFunctionArgs) {
|
||||
return {
|
||||
data: result.schedules.map((schedule) => ({
|
||||
id: schedule.friendlyId,
|
||||
type: schedule.type,
|
||||
task: schedule.taskIdentifier,
|
||||
generator: {
|
||||
type: "CRON",
|
||||
|
||||
@@ -37,7 +37,7 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
|
||||
}
|
||||
|
||||
function projectForUpdates(id: string) {
|
||||
return prisma.project.findUnique({
|
||||
return prisma.project.findFirst({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
|
||||
@@ -1080,7 +1080,7 @@ class SharedQueueTasks {
|
||||
|
||||
const variables = await this.#buildEnvironmentVariables(
|
||||
attempt.runtimeEnvironment,
|
||||
taskRun,
|
||||
taskRun.id,
|
||||
machinePreset
|
||||
);
|
||||
|
||||
@@ -1136,16 +1136,18 @@ class SharedQueueTasks {
|
||||
return;
|
||||
}
|
||||
|
||||
const run = await prisma.taskRun.findUnique({
|
||||
const run = await prisma.taskRun.findFirst({
|
||||
where: {
|
||||
id: runId,
|
||||
runtimeEnvironmentId: environment.id,
|
||||
},
|
||||
include: {
|
||||
lockedBy: true,
|
||||
_count: {
|
||||
select: {
|
||||
id: true,
|
||||
traceContext: true,
|
||||
friendlyId: true,
|
||||
isTest: true,
|
||||
lockedBy: {
|
||||
select: {
|
||||
attempts: true,
|
||||
machineConfig: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1156,9 +1158,20 @@ class SharedQueueTasks {
|
||||
return;
|
||||
}
|
||||
|
||||
const attemptCount = await prisma.taskRunAttempt.count({
|
||||
where: {
|
||||
taskRunId: run.id,
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug("Getting lazy attempt payload for run", {
|
||||
run,
|
||||
attemptCount,
|
||||
});
|
||||
|
||||
const machinePreset = machinePresetFromConfig(run.lockedBy?.machineConfig ?? {});
|
||||
|
||||
const variables = await this.#buildEnvironmentVariables(environment, run, machinePreset);
|
||||
const variables = await this.#buildEnvironmentVariables(environment, run.id, machinePreset);
|
||||
|
||||
return {
|
||||
traceContext: run.traceContext as Record<string, unknown>,
|
||||
@@ -1169,7 +1182,7 @@ class SharedQueueTasks {
|
||||
runId: run.friendlyId,
|
||||
messageId: run.id,
|
||||
isTest: run.isTest,
|
||||
attemptCount: run._count.attempts,
|
||||
attemptCount,
|
||||
} satisfies TaskRunExecutionLazyAttemptPayload;
|
||||
}
|
||||
|
||||
@@ -1203,13 +1216,13 @@ class SharedQueueTasks {
|
||||
|
||||
async #buildEnvironmentVariables(
|
||||
environment: RuntimeEnvironment,
|
||||
run: TaskRun,
|
||||
runId: string,
|
||||
machinePreset: MachinePreset
|
||||
): Promise<Array<EnvironmentVariable>> {
|
||||
const variables = await resolveVariablesForEnvironment(environment);
|
||||
|
||||
const jwt = await generateJWTTokenForEnvironment(environment, {
|
||||
run_id: run.id,
|
||||
run_id: runId,
|
||||
machine_preset: machinePreset.name,
|
||||
});
|
||||
|
||||
@@ -1217,7 +1230,7 @@ class SharedQueueTasks {
|
||||
...variables,
|
||||
...[
|
||||
{ key: "TRIGGER_JWT", value: jwt },
|
||||
{ key: "TRIGGER_RUN_ID", value: run.id },
|
||||
{ key: "TRIGGER_RUN_ID", value: runId },
|
||||
{
|
||||
key: "TRIGGER_MACHINE_PRESET",
|
||||
value: machinePreset.name,
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
import { ZodError } from "zod";
|
||||
import { CronPattern } from "../schedules";
|
||||
import { BaseService, ServiceValidationError } from "./baseService.server";
|
||||
import { getLimit } from "~/services/platform.v3.server";
|
||||
import { getTimezones } from "~/utils/timezones.server";
|
||||
import { env } from "~/env.server";
|
||||
|
||||
type Schedule = {
|
||||
cron: string;
|
||||
timezone?: string;
|
||||
taskIdentifier: string;
|
||||
friendlyId?: string;
|
||||
};
|
||||
|
||||
export class CheckScheduleService extends BaseService {
|
||||
public async call(projectId: string, schedule: Schedule) {
|
||||
//validate the cron expression
|
||||
try {
|
||||
CronPattern.parse(schedule.cron);
|
||||
} catch (e) {
|
||||
if (e instanceof ZodError) {
|
||||
throw new ServiceValidationError(`Invalid cron expression: ${e.issues[0].message}`);
|
||||
}
|
||||
|
||||
throw new ServiceValidationError(
|
||||
`Invalid cron expression: ${e instanceof Error ? e.message : JSON.stringify(e)}`
|
||||
);
|
||||
}
|
||||
|
||||
//chek it's a valid timezone
|
||||
if (schedule.timezone) {
|
||||
const possibleTimezones = getTimezones();
|
||||
if (!possibleTimezones.includes(schedule.timezone)) {
|
||||
throw new ServiceValidationError(
|
||||
`Invalid IANA timezone: '${schedule.timezone}'. View the list of valid timezones at ${env.APP_ORIGIN}/timezones`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//check the task exists
|
||||
const task = await this._prisma.backgroundWorkerTask.findFirst({
|
||||
where: {
|
||||
slug: schedule.taskIdentifier,
|
||||
projectId: projectId,
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
},
|
||||
});
|
||||
|
||||
if (!task) {
|
||||
throw new ServiceValidationError(
|
||||
`Task with identifier ${schedule.taskIdentifier} not found in project.`
|
||||
);
|
||||
}
|
||||
|
||||
if (task.triggerSource !== "SCHEDULED") {
|
||||
throw new ServiceValidationError(
|
||||
`Task with identifier ${schedule.taskIdentifier} is not a scheduled task.`
|
||||
);
|
||||
}
|
||||
|
||||
//if creating a schedule, check they're under the limits
|
||||
if (!schedule.friendlyId) {
|
||||
//check they're within their limit
|
||||
const project = await this._prisma.project.findFirst({
|
||||
where: {
|
||||
id: projectId,
|
||||
},
|
||||
select: {
|
||||
organizationId: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!project) {
|
||||
throw new ServiceValidationError("Project not found");
|
||||
}
|
||||
|
||||
const limit = await getLimit(project.organizationId, "schedules", 500);
|
||||
const schedulesCount = await this._prisma.taskSchedule.count({
|
||||
where: {
|
||||
projectId,
|
||||
},
|
||||
});
|
||||
|
||||
if (schedulesCount >= limit) {
|
||||
throw new ServiceValidationError(
|
||||
`You have created ${schedulesCount}/${limit} schedules so you'll need to increase your limits or delete some schedules.`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,9 @@ import { generateFriendlyId } from "../friendlyIdentifiers";
|
||||
import { calculateNextBuildVersion } from "../utils/calculateNextBuildVersion";
|
||||
import { BaseService } from "./baseService.server";
|
||||
import { projectPubSub } from "./projectPubSub.server";
|
||||
import { RegisterNextTaskScheduleInstanceService } from "./registerNextTaskScheduleInstance.server";
|
||||
import cronstrue from "cronstrue";
|
||||
import { CheckScheduleService } from "./checkSchedule.server";
|
||||
|
||||
export class CreateBackgroundWorkerService extends BaseService {
|
||||
public async call(
|
||||
@@ -68,6 +71,12 @@ export class CreateBackgroundWorkerService extends BaseService {
|
||||
});
|
||||
|
||||
await createBackgroundTasks(body.metadata.tasks, backgroundWorker, environment, this._prisma);
|
||||
await syncDeclarativeSchedules(
|
||||
body.metadata.tasks,
|
||||
backgroundWorker,
|
||||
environment,
|
||||
this._prisma
|
||||
);
|
||||
|
||||
try {
|
||||
//send a notification that a new worker has been created
|
||||
@@ -220,3 +229,155 @@ export async function createBackgroundTasks(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//CreateDeclarativeScheduleError with a message
|
||||
export class CreateDeclarativeScheduleError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = "CreateDeclarativeScheduleError";
|
||||
}
|
||||
}
|
||||
|
||||
export async function syncDeclarativeSchedules(
|
||||
tasks: TaskResource[],
|
||||
worker: BackgroundWorker,
|
||||
environment: AuthenticatedEnvironment,
|
||||
prisma: PrismaClientOrTransaction
|
||||
) {
|
||||
const tasksWithDeclarativeSchedules = tasks.filter((task) => task.schedule);
|
||||
logger.info("Syncing declarative schedules", {
|
||||
tasksWithDeclarativeSchedules,
|
||||
environment,
|
||||
});
|
||||
|
||||
const existingDeclarativeSchedules = await prisma.taskSchedule.findMany({
|
||||
where: {
|
||||
type: "DECLARATIVE",
|
||||
projectId: environment.projectId,
|
||||
},
|
||||
include: {
|
||||
instances: true,
|
||||
},
|
||||
});
|
||||
|
||||
const checkSchedule = new CheckScheduleService(prisma);
|
||||
const registerNextService = new RegisterNextTaskScheduleInstanceService(prisma);
|
||||
|
||||
//start out by assuming they're all missing
|
||||
const missingSchedules = new Set<string>(
|
||||
existingDeclarativeSchedules.map((schedule) => schedule.id)
|
||||
);
|
||||
|
||||
//create/update schedules (+ instances)
|
||||
for (const task of tasksWithDeclarativeSchedules) {
|
||||
if (task.schedule === undefined) continue;
|
||||
|
||||
const existingSchedule = existingDeclarativeSchedules.find(
|
||||
(schedule) =>
|
||||
schedule.taskIdentifier === task.id &&
|
||||
schedule.instances.some((instance) => instance.environmentId === environment.id)
|
||||
);
|
||||
|
||||
//this throws errors if the schedule is invalid
|
||||
await checkSchedule.call(environment.projectId, {
|
||||
cron: task.schedule.cron,
|
||||
timezone: task.schedule.timezone,
|
||||
taskIdentifier: task.id,
|
||||
friendlyId: existingSchedule?.friendlyId,
|
||||
});
|
||||
|
||||
if (existingSchedule) {
|
||||
const schedule = await prisma.taskSchedule.update({
|
||||
where: {
|
||||
id: existingSchedule.id,
|
||||
},
|
||||
data: {
|
||||
generatorExpression: task.schedule.cron,
|
||||
generatorDescription: cronstrue.toString(task.schedule.cron),
|
||||
timezone: task.schedule.timezone,
|
||||
},
|
||||
include: {
|
||||
instances: true,
|
||||
},
|
||||
});
|
||||
|
||||
missingSchedules.delete(existingSchedule.id);
|
||||
const instance = schedule.instances.at(0);
|
||||
if (instance) {
|
||||
await registerNextService.call(instance.id);
|
||||
} else {
|
||||
throw new CreateDeclarativeScheduleError(
|
||||
`Missing instance for declarative schedule ${schedule.id}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const newSchedule = await prisma.taskSchedule.create({
|
||||
data: {
|
||||
friendlyId: generateFriendlyId("sched"),
|
||||
projectId: environment.projectId,
|
||||
taskIdentifier: task.id,
|
||||
generatorExpression: task.schedule.cron,
|
||||
generatorDescription: cronstrue.toString(task.schedule.cron),
|
||||
timezone: task.schedule.timezone,
|
||||
type: "DECLARATIVE",
|
||||
instances: {
|
||||
create: [
|
||||
{
|
||||
environmentId: environment.id,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
include: {
|
||||
instances: true,
|
||||
},
|
||||
});
|
||||
|
||||
const instance = newSchedule.instances.at(0);
|
||||
|
||||
if (instance) {
|
||||
await registerNextService.call(instance.id);
|
||||
} else {
|
||||
throw new CreateDeclarativeScheduleError(
|
||||
`Missing instance for declarative schedule ${newSchedule.id}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Delete instances for this environment
|
||||
//Delete schedules that have no instances left
|
||||
const potentiallyDeletableSchedules = await prisma.taskSchedule.findMany({
|
||||
where: {
|
||||
id: {
|
||||
in: Array.from(missingSchedules),
|
||||
},
|
||||
},
|
||||
include: {
|
||||
instances: true,
|
||||
},
|
||||
});
|
||||
|
||||
for (const schedule of potentiallyDeletableSchedules) {
|
||||
const canDeleteSchedule =
|
||||
schedule.instances.length === 0 ||
|
||||
schedule.instances.every((instance) => instance.environmentId === environment.id);
|
||||
|
||||
if (canDeleteSchedule) {
|
||||
//we can delete schedules with no instances other than ones for the current environment
|
||||
await prisma.taskSchedule.delete({
|
||||
where: {
|
||||
id: schedule.id,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
//otherwise we delete the instance (other environments remain untouched)
|
||||
await prisma.taskScheduleInstance.deleteMany({
|
||||
where: {
|
||||
taskScheduleId: schedule.id,
|
||||
environmentId: environment.id,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { BackgroundWorker } from "@trigger.dev/database";
|
||||
import { AuthenticatedEnvironment } from "~/services/apiAuth.server";
|
||||
import { generateFriendlyId } from "../friendlyIdentifiers";
|
||||
import { BaseService } from "./baseService.server";
|
||||
import { createBackgroundTasks } from "./createBackgroundWorker.server";
|
||||
import { createBackgroundTasks, syncDeclarativeSchedules } from "./createBackgroundWorker.server";
|
||||
import { CURRENT_DEPLOYMENT_LABEL } from "~/consts";
|
||||
import { projectPubSub } from "./projectPubSub.server";
|
||||
import { marqs } from "~/v3/marqs/index.server";
|
||||
@@ -50,7 +50,39 @@ export class CreateDeployedBackgroundWorkerService extends BaseService {
|
||||
},
|
||||
});
|
||||
|
||||
await createBackgroundTasks(body.metadata.tasks, backgroundWorker, environment, this._prisma);
|
||||
try {
|
||||
await createBackgroundTasks(
|
||||
body.metadata.tasks,
|
||||
backgroundWorker,
|
||||
environment,
|
||||
this._prisma
|
||||
);
|
||||
await syncDeclarativeSchedules(
|
||||
body.metadata.tasks,
|
||||
backgroundWorker,
|
||||
environment,
|
||||
this._prisma
|
||||
);
|
||||
} catch (error) {
|
||||
const name = error instanceof Error ? error.name : "UnknownError";
|
||||
const message = error instanceof Error ? error.message : JSON.stringify(error);
|
||||
|
||||
await this._prisma.workerDeployment.update({
|
||||
where: {
|
||||
id: deployment.id,
|
||||
},
|
||||
data: {
|
||||
status: "FAILED",
|
||||
failedAt: new Date(),
|
||||
errorData: {
|
||||
name,
|
||||
message,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Link the deployment with the background worker
|
||||
await this._prisma.workerDeployment.update({
|
||||
|
||||
@@ -27,6 +27,20 @@ export class DeleteTaskScheduleService extends BaseService {
|
||||
}
|
||||
|
||||
try {
|
||||
const schedule = await this._prisma.taskSchedule.findFirst({
|
||||
where: {
|
||||
friendlyId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!schedule) {
|
||||
throw new Error("Schedule not found");
|
||||
}
|
||||
|
||||
if (schedule.type === "DECLARATIVE") {
|
||||
throw new Error("Cannot delete declarative schedules");
|
||||
}
|
||||
|
||||
await this._prisma.taskSchedule.delete({
|
||||
where: {
|
||||
friendlyId,
|
||||
|
||||
@@ -28,6 +28,20 @@ export class SetActiveOnTaskScheduleService extends BaseService {
|
||||
}
|
||||
|
||||
try {
|
||||
const schedule = await this._prisma.taskSchedule.findFirst({
|
||||
where: {
|
||||
friendlyId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!schedule) {
|
||||
throw new Error("Schedule not found");
|
||||
}
|
||||
|
||||
if (schedule.type === "DECLARATIVE") {
|
||||
throw new Error("Cannot enable/disable declarative schedules");
|
||||
}
|
||||
|
||||
await this._prisma.taskSchedule.update({
|
||||
where: {
|
||||
friendlyId,
|
||||
|
||||
@@ -24,6 +24,7 @@ export class TestTaskService extends BaseService {
|
||||
case "SCHEDULED": {
|
||||
const payload = {
|
||||
scheduleId: "sched_1234",
|
||||
type: "IMPERATIVE",
|
||||
timestamp: data.timestamp,
|
||||
lastTimestamp: data.lastTimestamp,
|
||||
timezone: data.timezone,
|
||||
|
||||
@@ -94,6 +94,7 @@ export class TriggerScheduledTaskService extends BaseService {
|
||||
|
||||
const payload = {
|
||||
scheduleId: instance.taskSchedule.friendlyId,
|
||||
type: instance.taskSchedule.type,
|
||||
timestamp: instance.nextScheduledTimestamp,
|
||||
lastTimestamp: instance.lastScheduledTimestamp ?? undefined,
|
||||
externalId: instance.taskSchedule.externalId ?? undefined,
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
import { Prisma, TaskSchedule } from "@trigger.dev/database";
|
||||
import cronstrue from "cronstrue";
|
||||
import { nanoid } from "nanoid";
|
||||
import { ZodError } from "zod";
|
||||
import { $transaction, PrismaClientOrTransaction } from "~/db.server";
|
||||
import { generateFriendlyId } from "../friendlyIdentifiers";
|
||||
import { CronPattern, UpsertSchedule } from "../schedules";
|
||||
import { BaseService, ServiceValidationError } from "./baseService.server";
|
||||
import { RegisterNextTaskScheduleInstanceService } from "./registerNextTaskScheduleInstance.server";
|
||||
import cronstrue from "cronstrue";
|
||||
import { UpsertSchedule } from "../schedules";
|
||||
import { calculateNextScheduledTimestamp } from "../utils/calculateNextSchedule.server";
|
||||
import { getTimezones } from "~/utils/timezones.server";
|
||||
import { env } from "~/env.server";
|
||||
import { getLimit } from "~/services/platform.v3.server";
|
||||
import { BaseService, ServiceValidationError } from "./baseService.server";
|
||||
import { CheckScheduleService } from "./checkSchedule.server";
|
||||
import { RegisterNextTaskScheduleInstanceService } from "./registerNextTaskScheduleInstance.server";
|
||||
|
||||
export type UpsertTaskScheduleServiceOptions = UpsertSchedule;
|
||||
|
||||
@@ -30,79 +27,9 @@ type InstanceWithEnvironment = Prisma.TaskScheduleInstanceGetPayload<{
|
||||
|
||||
export class UpsertTaskScheduleService extends BaseService {
|
||||
public async call(projectId: string, schedule: UpsertTaskScheduleServiceOptions) {
|
||||
//validate the cron expression
|
||||
try {
|
||||
CronPattern.parse(schedule.cron);
|
||||
} catch (e) {
|
||||
if (e instanceof ZodError) {
|
||||
throw new ServiceValidationError(`Invalid cron expression: ${e.issues[0].message}`);
|
||||
}
|
||||
|
||||
throw new ServiceValidationError(
|
||||
`Invalid cron expression: ${e instanceof Error ? e.message : JSON.stringify(e)}`
|
||||
);
|
||||
}
|
||||
|
||||
const task = await this._prisma.backgroundWorkerTask.findFirst({
|
||||
where: {
|
||||
slug: schedule.taskIdentifier,
|
||||
projectId: projectId,
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
},
|
||||
});
|
||||
|
||||
if (!task) {
|
||||
throw new ServiceValidationError(
|
||||
`Task with identifier ${schedule.taskIdentifier} not found in project.`
|
||||
);
|
||||
}
|
||||
|
||||
if (task.triggerSource !== "SCHEDULED") {
|
||||
throw new ServiceValidationError(
|
||||
`Task with identifier ${schedule.taskIdentifier} is not a scheduled task.`
|
||||
);
|
||||
}
|
||||
|
||||
//if creating a schedule, check they're under the limits
|
||||
if (!schedule.friendlyId) {
|
||||
//check they're within their limit
|
||||
const project = await this._prisma.project.findFirst({
|
||||
where: {
|
||||
id: projectId,
|
||||
},
|
||||
select: {
|
||||
organizationId: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!project) {
|
||||
throw new ServiceValidationError("Project not found");
|
||||
}
|
||||
|
||||
const limit = await getLimit(project.organizationId, "schedules", 500);
|
||||
const schedulesCount = await this._prisma.taskSchedule.count({
|
||||
where: {
|
||||
projectId,
|
||||
},
|
||||
});
|
||||
|
||||
if (schedulesCount >= limit) {
|
||||
throw new ServiceValidationError(
|
||||
`You have created ${schedulesCount}/${limit} schedules so you'll need to increase your limits or delete some schedules. Increase your limits by contacting support.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (schedule.timezone) {
|
||||
const possibleTimezones = getTimezones();
|
||||
if (!possibleTimezones.includes(schedule.timezone)) {
|
||||
throw new ServiceValidationError(
|
||||
`Invalid IANA timezone: "${schedule.timezone}". View the list of valid timezones at ${env.APP_ORIGIN}/timezones`
|
||||
);
|
||||
}
|
||||
}
|
||||
//this throws errors if the schedule is invalid
|
||||
const checkSchedule = new CheckScheduleService(this._prisma);
|
||||
await checkSchedule.call(projectId, schedule);
|
||||
|
||||
const result = await $transaction(this._prisma, async (tx) => {
|
||||
const deduplicationKey =
|
||||
@@ -126,6 +53,10 @@ export class UpsertTaskScheduleService extends BaseService {
|
||||
});
|
||||
|
||||
if (existingSchedule) {
|
||||
if (existingSchedule.type === "DECLARATIVE") {
|
||||
throw new ServiceValidationError("Cannot update a declarative schedule");
|
||||
}
|
||||
|
||||
return await this.#updateExistingSchedule(tx, existingSchedule, schedule, projectId);
|
||||
} else {
|
||||
return await this.#createNewSchedule(tx, schedule, projectId, deduplicationKey);
|
||||
@@ -317,6 +248,7 @@ export class UpsertTaskScheduleService extends BaseService {
|
||||
#createReturnObject(taskSchedule: TaskSchedule, instances: InstanceWithEnvironment[]) {
|
||||
return {
|
||||
id: taskSchedule.friendlyId,
|
||||
type: taskSchedule.type,
|
||||
task: taskSchedule.taskIdentifier,
|
||||
active: taskSchedule.active,
|
||||
externalId: taskSchedule.externalId,
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ RUN pnpm run build --filter=webapp...
|
||||
|
||||
# Runner
|
||||
FROM node:20.11.1-bullseye-slim@sha256:5a5a92b3a8d392691c983719dbdc65d9f30085d6dcd65376e7a32e6fe9bf4cbe AS runner
|
||||
RUN apt-get update && apt-get install -y openssl
|
||||
RUN apt-get update && apt-get install -y openssl netcat-openbsd
|
||||
WORKDIR /triggerdotdev
|
||||
RUN corepack enable
|
||||
ENV NODE_ENV production
|
||||
|
||||
@@ -16,7 +16,7 @@ paths:
|
||||
post:
|
||||
operationId: create_schedule_v1
|
||||
summary: Create a schedule
|
||||
description: Create a new schedule based on the specified options.
|
||||
description: Create a new `IMPERATIVE` schedule based on the specified options.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
@@ -127,7 +127,7 @@ paths:
|
||||
put:
|
||||
operationId: update_schedule_v1
|
||||
summary: Update Schedule
|
||||
description: Update a schedule by its ID.
|
||||
description: Update a schedule by its ID. This will only work on `IMPERATIVE` schedules that were created in the dashboard or using the imperative SDK functions like `schedules.create()`.
|
||||
parameters:
|
||||
- in: path
|
||||
name: schedule_id
|
||||
@@ -173,7 +173,7 @@ paths:
|
||||
delete:
|
||||
operationId: delete_schedule_v1
|
||||
summary: Delete Schedule
|
||||
description: Delete a schedule by its ID.
|
||||
description: Delete a schedule by its ID. This will only work on `IMPERATIVE` schedules that were created in the dashboard or using the imperative SDK functions like `schedules.create()`.
|
||||
parameters:
|
||||
- in: path
|
||||
name: schedule_id
|
||||
@@ -203,7 +203,7 @@ paths:
|
||||
post:
|
||||
operationId: deactivate_schedule_v1
|
||||
summary: Deactivate Schedule.
|
||||
description: Deactivate a schedule by its ID.
|
||||
description: Deactivate a schedule by its ID. This will only work on `IMPERATIVE` schedules that were created in the dashboard or using the imperative SDK functions like `schedules.create()`.
|
||||
parameters:
|
||||
- in: path
|
||||
name: schedule_id
|
||||
@@ -237,7 +237,7 @@ paths:
|
||||
post:
|
||||
operationId: activate_schedule_v1
|
||||
summary: Activate Schedule
|
||||
description: Activate a schedule by its ID.
|
||||
description: Activate a schedule by its ID. This will only work on `IMPERATIVE` schedules that were created in the dashboard or using the imperative SDK functions like `schedules.create()`.
|
||||
parameters:
|
||||
- in: path
|
||||
name: schedule_id
|
||||
@@ -1971,6 +1971,10 @@ components:
|
||||
example: my-scheduled-task
|
||||
description: The id of the scheduled task that will be triggered by this
|
||||
schedule
|
||||
"type":
|
||||
type: string
|
||||
example: IMPERATIVE
|
||||
description: The type of schedule, `DECLARATIVE` or `IMPERATIVE`. Declarative schedules are declared in your code by setting the `cron` property on a `schedules.task`. Imperative schedules are created in the dashboard or by using the imperative SDK functions like `schedules.create()`.
|
||||
active:
|
||||
type: boolean
|
||||
example: true
|
||||
|
||||
+62
-10
@@ -3,21 +3,13 @@ title: "Scheduled tasks"
|
||||
description: "A task that is triggered on a recurring schedule using CRON syntax."
|
||||
---
|
||||
|
||||
To use scheduled tasks you need to do two things:
|
||||
|
||||
1. Define a task in your code using `schedules.task()`.
|
||||
2. Attach a schedule to the task either using the dashboard or the SDK.
|
||||
|
||||
<Info>A task can have multiple schedules attached to it.</Info>
|
||||
|
||||
Like all tasks they don't have timeouts, they should be placed inside a [/trigger folder](/v3/trigger-folder), and you [can configure them](/v3/tasks-overview#defining-a-task).
|
||||
|
||||
## Defining a scheduled task
|
||||
|
||||
This task will run when any of the attached schedules trigger. They have a predefined payload with some useful properties:
|
||||
|
||||
```ts
|
||||
import { schedules } from "@trigger.dev/sdk/v3";
|
||||
|
||||
//this task will run when any of the attached schedules trigger
|
||||
export const firstScheduledTask = schedules.task({
|
||||
id: "first-scheduled-task",
|
||||
run: async (payload) => {
|
||||
@@ -68,6 +60,66 @@ You can see from the comments that the payload has several useful properties:
|
||||
to do that.
|
||||
</Note>
|
||||
|
||||
Like all tasks they don't have timeouts, they should be placed inside a [/trigger folder](/v3/trigger-folder), and you [can configure them](/v3/tasks-overview#defining-a-task).
|
||||
|
||||
## How to attach a schedule
|
||||
|
||||
Now that we've defined a scheduled task, we need to define when it will actually run. To do this we need to attach one or more schedules.
|
||||
|
||||
There are two ways of doing this:
|
||||
|
||||
- **Declarative:** defined on your `schedules.task`. They sync when you run the dev command or deploy.
|
||||
- **Imperative:** created from the dashboard or by using the imperative SDK functions like `schedules.create()`.
|
||||
|
||||
<Info>
|
||||
A scheduled task can have multiple schedules attached to it, including a declarative schedule
|
||||
and/or many imperative schedules.
|
||||
</Info>
|
||||
|
||||
### Declarative schedules
|
||||
|
||||
These sync when you run the [dev](/v3/cli-dev) or [deploy](/v3/cli-deploy) commands.
|
||||
|
||||
To create them you add the `cron` property to your `schedules.task()`. This property is optional and is only used if you want to add a declarative schedule to your task:
|
||||
|
||||
```ts
|
||||
export const firstScheduledTask = schedules.task({
|
||||
id: "first-scheduled-task",
|
||||
//every two hours (UTC timezone)
|
||||
cron: "0 */2 * * *",
|
||||
run: async (payload, { ctx }) => {
|
||||
//do something
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
If you use a string it will be in UTC. Alternatively, you can specify a timezone like this:
|
||||
|
||||
```ts
|
||||
export const secondScheduledTask = schedules.task({
|
||||
id: "second-scheduled-task",
|
||||
cron: {
|
||||
//5am every day Tokyo time
|
||||
pattern: "0 5 * * *",
|
||||
timezone: "Asia/Tokyo",
|
||||
},
|
||||
run: async (payload) => {},
|
||||
});
|
||||
```
|
||||
|
||||
When you run the [dev](/v3/cli-dev) or [deploy](/v3/cli-deploy) commands, declarative schedules will be synced. If you add, delete or edit the `cron` property it will be updated when you run these commands. You can view your schedules on the Schedules page in the dashboard.
|
||||
|
||||
### Imperative schedules
|
||||
|
||||
Alternatively you can explicitly attach schedules to a `schedules.task`. You can do this in the Schedules page in the dashboard by just pressing the "New schedule" button, or you can use the SDK to create schedules.
|
||||
|
||||
The advantage of imperative schedules is that they can be created dynamically, for example, you could create a schedule for each user in your database. They can also be activated, disabled, edited, and deleted without deploying new code by using the SDK or dashboard.
|
||||
|
||||
To use imperative schedules you need to do two things:
|
||||
|
||||
1. Define a task in your code using `schedules.task()`.
|
||||
2. Attach 1+ schedules to the task either using the dashboard or the SDK.
|
||||
|
||||
## Supported CRON syntax
|
||||
|
||||
```
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @trigger.dev/airtable
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
- @trigger.dev/integration-kit@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/airtable",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "Trigger.dev integration for airtable",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -25,8 +25,8 @@
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.50",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"airtable": "^0.12.1",
|
||||
"zod": "3.22.3"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @trigger.dev/github
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
- @trigger.dev/integration-kit@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/github",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "The official GitHub integration for Trigger.dev",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -30,8 +30,8 @@
|
||||
"@octokit/request-error": "^5.0.1",
|
||||
"@octokit/webhooks": "^12.0.10",
|
||||
"octokit": "^3.1.2",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.50",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"zod": "3.22.3"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @trigger.dev/linear
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
- @trigger.dev/integration-kit@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/linear",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "Trigger.dev integration for @linear/sdk",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -26,8 +26,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@linear/sdk": "^8.0.0",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.50",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"zod": "3.22.3"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @trigger.dev/slack
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
- @trigger.dev/integration-kit@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/openai",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "The official OpenAI integration for Trigger.dev",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -42,8 +42,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"openai": "^4.16.1",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.49"
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.50"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @trigger.dev/plain
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
- @trigger.dev/integration-kit@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/plain",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "The official Plain.com integration for Trigger.dev",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -24,8 +24,8 @@
|
||||
"build:tsup": "tsup"
|
||||
},
|
||||
"dependencies": {
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.50",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"@team-plain/typescript-sdk": "^2.7.0"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @trigger.dev/replicate
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
- @trigger.dev/integration-kit@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/replicate",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "Trigger.dev integration for replicate",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -25,8 +25,8 @@
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.50",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"replicate": "^0.18.1",
|
||||
"zod": "3.22.3"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @trigger.dev/resend
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
- @trigger.dev/integration-kit@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/resend",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "The official Resend.com integration for Trigger.dev",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -24,8 +24,8 @@
|
||||
"build:tsup": "tsup"
|
||||
},
|
||||
"dependencies": {
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.50",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"resend": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @trigger.dev/sendgrid
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
- @trigger.dev/integration-kit@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/sendgrid",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "Trigger.dev integration for @sendgrid/mail",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -26,8 +26,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@sendgrid/mail": "^7.7.0",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.49"
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.50"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.8.0"
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @trigger.dev/shopify
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
- @trigger.dev/integration-kit@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/shopify",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "Trigger.dev integration for @shopify/shopify-api",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -26,8 +26,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@shopify/shopify-api": "^8.0.2",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.50",
|
||||
"zod": "3.22.3"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @trigger.dev/slack
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/slack",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "The official Slack integration for Trigger.dev",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -25,7 +25,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@slack/web-api": "^6.8.1",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"zod": "3.22.3"
|
||||
},
|
||||
"engines": {
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @trigger.dev/stripe
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
- @trigger.dev/integration-kit@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/stripe",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "Trigger.dev integration for stripe",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -25,8 +25,8 @@
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.50",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"stripe": "^12.14.0",
|
||||
"zod": "3.22.3"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @trigger.dev/supabase
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
- @trigger.dev/integration-kit@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/supabase",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "Trigger.dev integration for @supabase/supabase-js",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -26,8 +26,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@supabase/supabase-js": "^2.26.0",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.50",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"supabase-management-js": "^1.0.0",
|
||||
"zod": "3.22.3"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @trigger.dev/typeform
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
- @trigger.dev/integration-kit@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/typeform",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "The official Typeform integration for Trigger.dev",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -24,8 +24,8 @@
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"dependencies": {
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.50",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"@typeform/api-client": "^1.8.0",
|
||||
"zod": "3.22.3"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @trigger.dev/astro
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@trigger.dev/astro",
|
||||
"description": "An Astro-native integration for Trigger.dev background jobs platform",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"files": [
|
||||
@@ -20,7 +20,7 @@
|
||||
"build:tsup": "tsup"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49"
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50"
|
||||
},
|
||||
"devDependencies": {
|
||||
"astro": "^3.0.12",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# trigger.dev
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/core@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "trigger.dev",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "A Command-Line Interface for Trigger.dev (v3) projects",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -87,7 +87,7 @@
|
||||
"@opentelemetry/sdk-trace-base": "^1.22.0",
|
||||
"@opentelemetry/sdk-trace-node": "^1.22.0",
|
||||
"@opentelemetry/semantic-conventions": "^1.22.0",
|
||||
"@trigger.dev/core": "workspace:3.0.0-beta.49",
|
||||
"@trigger.dev/core": "workspace:3.0.0-beta.50",
|
||||
"@types/degit": "^2.8.3",
|
||||
"chalk": "^5.2.0",
|
||||
"chokidar": "^3.5.3",
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# create-trigger
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/core@3.0.0-beta.50
|
||||
- @trigger.dev/yalt@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/cli",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "The Trigger.dev CLI",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# @trigger.dev/core-apps
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
## 3.0.0-beta.48
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@trigger.dev/core-apps",
|
||||
"description": "Backend core code used across apps",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# @trigger.dev/core-backend
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
## 3.0.0-beta.48
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/core-backend",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "Core code used across `@trigger.dev/sdk` and Trigger.dev server",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# internal-platform
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 8ba998794: Added declarative cron schedules
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/core",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "Core code used across the Trigger.dev SDK and platform",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
|
||||
@@ -226,10 +226,19 @@ export const CanceledRunResponse = z.object({
|
||||
|
||||
export type CanceledRunResponse = z.infer<typeof CanceledRunResponse>;
|
||||
|
||||
export const ScheduleType = z.union([z.literal("DECLARATIVE"), z.literal("IMPERATIVE")]);
|
||||
|
||||
export const ScheduledTaskPayload = z.object({
|
||||
/** The schedule id associated with this run (you can have many schedules for the same task).
|
||||
You can use this to remove the schedule, update it, etc */
|
||||
scheduleId: z.string(),
|
||||
/** The type of schedule – `"DECLARATIVE"` or `"IMPERATIVE"`.
|
||||
*
|
||||
* **DECLARATIVE** – defined inline on your `schedules.task` using the `cron` property. They can only be created, updated or deleted by modifying the `cron` property on your task.
|
||||
*
|
||||
* **IMPERATIVE** – created using the `schedules.create` functions or in the dashboard.
|
||||
*/
|
||||
type: ScheduleType,
|
||||
/** When the task was scheduled to run.
|
||||
* Note this will be slightly different from `new Date()` because it takes a few ms to run the task.
|
||||
*
|
||||
@@ -315,6 +324,7 @@ export type ScheduleGenerator = z.infer<typeof ScheduleGenerator>;
|
||||
|
||||
export const ScheduleObject = z.object({
|
||||
id: z.string(),
|
||||
type: ScheduleType,
|
||||
task: z.string(),
|
||||
active: z.boolean(),
|
||||
deduplicationKey: z.string().nullish(),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { z } from "zod";
|
||||
import { QueueOptions, RetryOptions } from "./schemas";
|
||||
import { QueueOptions, RetryOptions, ScheduleMetadata } from "./schemas";
|
||||
import { MachineConfig } from "./common";
|
||||
|
||||
export const TaskResource = z.object({
|
||||
@@ -10,6 +10,7 @@ export const TaskResource = z.object({
|
||||
retry: RetryOptions.optional(),
|
||||
machine: MachineConfig.optional(),
|
||||
triggerSource: z.string().optional(),
|
||||
schedule: ScheduleMetadata.optional(),
|
||||
});
|
||||
|
||||
export type TaskResource = z.infer<typeof TaskResource>;
|
||||
|
||||
@@ -142,6 +142,11 @@ export const QueueOptions = z.object({
|
||||
|
||||
export type QueueOptions = z.infer<typeof QueueOptions>;
|
||||
|
||||
export const ScheduleMetadata = z.object({
|
||||
cron: z.string(),
|
||||
timezone: z.string(),
|
||||
});
|
||||
|
||||
export const TaskMetadata = z.object({
|
||||
id: z.string(),
|
||||
packageVersion: z.string(),
|
||||
@@ -149,6 +154,7 @@ export const TaskMetadata = z.object({
|
||||
retry: RetryOptions.optional(),
|
||||
machine: MachineConfig.optional(),
|
||||
triggerSource: z.string().optional(),
|
||||
schedule: ScheduleMetadata.optional(),
|
||||
});
|
||||
|
||||
export type TaskMetadata = z.infer<typeof TaskMetadata>;
|
||||
@@ -167,6 +173,7 @@ export const TaskMetadataWithFilePath = z.object({
|
||||
retry: RetryOptions.optional(),
|
||||
machine: MachineConfig.optional(),
|
||||
triggerSource: z.string().optional(),
|
||||
schedule: ScheduleMetadata.optional(),
|
||||
filePath: z.string(),
|
||||
exportName: z.string(),
|
||||
});
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ScheduleType" AS ENUM ('DECLARATIVE', 'IMPERATIVE');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "TaskSchedule"
|
||||
ADD COLUMN "type" "ScheduleType" NOT NULL DEFAULT 'IMPERATIVE';
|
||||
@@ -2231,6 +2231,8 @@ model WorkerDeploymentPromotion {
|
||||
model TaskSchedule {
|
||||
id String @id @default(cuid())
|
||||
|
||||
type ScheduleType @default(IMPERATIVE)
|
||||
|
||||
///users see this as `id`. They start with schedule_
|
||||
friendlyId String @unique
|
||||
///a reference to a task (not a foreign key because it's across versions)
|
||||
@@ -2267,6 +2269,13 @@ model TaskSchedule {
|
||||
@@unique([projectId, deduplicationKey])
|
||||
}
|
||||
|
||||
enum ScheduleType {
|
||||
/// defined on your task using the `cron` property
|
||||
DECLARATIVE
|
||||
/// explicit calls to the SDK are used to create, or using the dashboard
|
||||
IMPERATIVE
|
||||
}
|
||||
|
||||
enum ScheduleGeneratorType {
|
||||
CRON
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# @trigger.dev/eslint-plugin
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
## 3.0.0-beta.48
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/eslint-plugin",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "ESLint plugin with trigger.dev best practices",
|
||||
"keywords": [
|
||||
"eslint",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @trigger.dev/express
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/express",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "Official Express adapter for Trigger.dev",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
@@ -23,7 +23,7 @@
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"@trigger.dev/tsconfig": "workspace:*",
|
||||
"@types/debug": "^4.1.7",
|
||||
"@types/express": "^4.17.13",
|
||||
@@ -39,7 +39,7 @@
|
||||
"build:tsup": "tsup"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49"
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @trigger.dev/hono
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/hono",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "A Trigger.dev adapter for Hono.dev",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
@@ -32,7 +32,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"hono": "3.x",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49"
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@trigger.dev/tsconfig": "workspace:*",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @trigger.dev/integration-kit
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/core@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/integration-kit",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "Trigger.dev Integration Kit has helpers to make creating integrations easier",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @trigger.dev/nestjs
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/nestjs",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "Official NestJS adapter for Trigger.dev",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
@@ -23,7 +23,7 @@
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"@trigger.dev/tsconfig": "workspace:*",
|
||||
"@types/debug": "^4.1.7",
|
||||
"@types/express": "^4.17.13",
|
||||
@@ -41,7 +41,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@nestjs/common": ">=10.0.0",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49"
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nestjs/common": "^10.2.4",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @trigger.dev/nextjs
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/nextjs",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "Trigger.dev Next.js integration",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
@@ -41,7 +41,7 @@
|
||||
"build:tsup": "tsup"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"next": ">=12.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# @trigger.dev/otlp-importer
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
## 3.0.0-beta.48
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/otlp-importer",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "OpenTelemetry OTLP Importer for Node.js written in TypeScript",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @trigger.dev/react
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/core@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/react",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "Trigger.dev React SDK",
|
||||
"license": "MIT",
|
||||
"types": "dist/index.d.ts",
|
||||
@@ -27,7 +27,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@tanstack/react-query": "5.0.0-beta.2",
|
||||
"@trigger.dev/core": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/core": "workspace:^3.0.0-beta.50",
|
||||
"debug": "^4.3.4",
|
||||
"zod": "3.22.3"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @trigger.dev/remix
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/remix",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "Trigger.dev Remix integration",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
@@ -39,7 +39,7 @@
|
||||
"build:tsup": "tsup"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49",
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50",
|
||||
"@remix-run/server-runtime": ">1.19.0"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# @trigger.dev/sveltekit
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/sveltekit",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "Trigger.dev svelteKit integration",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
@@ -39,7 +39,7 @@
|
||||
"build:tsup": "tsup"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.49"
|
||||
"@trigger.dev/sdk": "workspace:^3.0.0-beta.50"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4"
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @trigger.dev/testing
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/sdk@3.0.0-beta.50
|
||||
- @trigger.dev/core@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@trigger.dev/testing",
|
||||
"description": "A collection of useful tools to write tests for Trigger.dev.",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
# @trigger.dev/sdk
|
||||
|
||||
## 3.0.0-beta.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 8ba998794: Added declarative cron schedules
|
||||
- Updated dependencies [8ba998794]
|
||||
- @trigger.dev/core@3.0.0-beta.50
|
||||
- @trigger.dev/core-backend@3.0.0-beta.50
|
||||
|
||||
## 3.0.0-beta.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@trigger.dev/sdk",
|
||||
"version": "3.0.0-beta.49",
|
||||
"version": "3.0.0-beta.50",
|
||||
"description": "trigger.dev Node.JS SDK",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
@@ -48,8 +48,8 @@
|
||||
"@opentelemetry/api": "^1.8.0",
|
||||
"@opentelemetry/api-logs": "^0.48.0",
|
||||
"@opentelemetry/semantic-conventions": "^1.22.0",
|
||||
"@trigger.dev/core": "workspace:3.0.0-beta.49",
|
||||
"@trigger.dev/core-backend": "workspace:3.0.0-beta.49",
|
||||
"@trigger.dev/core": "workspace:3.0.0-beta.50",
|
||||
"@trigger.dev/core-backend": "workspace:3.0.0-beta.50",
|
||||
"chalk": "^5.2.0",
|
||||
"cronstrue": "^2.21.0",
|
||||
"debug": "^4.3.4",
|
||||
|
||||
@@ -16,13 +16,57 @@ import { Task, TaskOptions, apiClientMissingError, createTask } from "../shared"
|
||||
import * as SchedulesAPI from "./api";
|
||||
import { tracer } from "../tracer";
|
||||
|
||||
export type ScheduleOptions<
|
||||
TIdentifier extends string,
|
||||
TOutput,
|
||||
TInitOutput extends InitOutput,
|
||||
> = TaskOptions<TIdentifier, SchedulesAPI.ScheduledTaskPayload, TOutput, TInitOutput> & {
|
||||
/** You can optionally specify a CRON schedule on your task. You can also dynamically add a schedule in the dashboard or using the SDK functions.
|
||||
*
|
||||
* 1. Pass a CRON pattern string
|
||||
* ```ts
|
||||
* "0 0 * * *"
|
||||
* ```
|
||||
*
|
||||
* 2. Or an object with a pattern and an optional timezone (default is "UTC")
|
||||
* ```ts
|
||||
* {
|
||||
* pattern: "0 0 * * *",
|
||||
* timezone: "America/Los_Angeles"
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @link https://trigger.dev/docs/v3/tasks-scheduled
|
||||
*/
|
||||
cron?:
|
||||
| string
|
||||
| {
|
||||
pattern: string;
|
||||
timezone?: string;
|
||||
};
|
||||
};
|
||||
|
||||
export function task<TIdentifier extends string, TOutput, TInitOutput extends InitOutput>(
|
||||
params: TaskOptions<TIdentifier, SchedulesAPI.ScheduledTaskPayload, TOutput, TInitOutput>
|
||||
params: ScheduleOptions<TIdentifier, TOutput, TInitOutput>
|
||||
): Task<TIdentifier, SchedulesAPI.ScheduledTaskPayload, TOutput> {
|
||||
const task = createTask(params);
|
||||
|
||||
const cron = params.cron
|
||||
? typeof params.cron === "string"
|
||||
? params.cron
|
||||
: params.cron.pattern
|
||||
: undefined;
|
||||
const timezone =
|
||||
(params.cron && typeof params.cron !== "string" ? params.cron.timezone : "UTC") ?? "UTC";
|
||||
|
||||
taskCatalog.updateTaskMetadata(task.id, {
|
||||
triggerSource: "schedule",
|
||||
schedule: cron
|
||||
? {
|
||||
cron: cron,
|
||||
timezone,
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
|
||||
return task;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user