Compare commits

...

19 Commits

Author SHA1 Message Date
Eric Allam 6f9f25481e Update pnpm lock file 2024-03-28 19:55:14 +00:00
github-actions[bot] 67aaffb6fc chore: Update version for release (beta) (#984)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-28 19:54:21 +00:00
Eric Allam e3cf456c69 v3: fix string and non-standard outputs (#983)
* Fixed string outputs missing and incorrectly formatted

* Handle non-serializable outputs like a function

* Add changeset
2024-03-28 19:51:29 +00:00
Matt Aitken bf7827e7b8 Fix for the test latest runs showing other environments 2024-03-28 18:14:47 +00:00
Eric Allam bc020a3ffe Get the internal telemetry ready for test/prod 2024-03-28 18:12:01 +00:00
Eric Allam b361afbfe4 Update pnpm lock file 2024-03-28 16:29:17 +00:00
github-actions[bot] a3d809740d chore: Update version for release (beta) (#979)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-28 16:28:41 +00:00
Eric Allam f93eae300e v3: superjson dynamic import and deploy fixes (#982)
* v3: Dynamically import superjson and fix some bundling issues

* Added changeset

* Better error handling in the registry proxy and catch uncaught exceptions and unhandled promise rejections instead of crashing the server

* Await the prettyPrintPackage
2024-03-28 16:22:00 +00:00
Matt Aitken a2365e406d Fixed v3 docs link in the sidebar 2024-03-28 14:46:47 +00:00
Eric Allam 42d319c2d1 Remove all the v3-catalog code for triggering in code 2024-03-28 14:33:01 +00:00
nicktrn b66d5525ef v3: machine config (#978)
* add and use machine config

* assign tasks to worker nodes only

* add secure flag to zod connection

* changeset

* add pre stop hook

* don't use secure connection by default

* pass more identifiers to provider and apply labels
2024-03-28 14:21:49 +00:00
Eric Allam 719c0a0b94 v3: better clock management for spans/logs in CRIU envs (#980)
* durable clock WIP

* Fixed incorrect span timings around checkpoints by implementing a precise wall clock that resets after restores

* Add changeset
2024-03-28 14:20:44 +00:00
Matt Aitken f1c768a255 Docs for API keys, fixed links to docs from app (#981)
* Add missing API keys docs and link from the web app to them. Renamed Server API keys to Secret keys

* Correct link to env var docs

* Duplicate image fixed on environment variables docs
2024-03-28 14:00:42 +00:00
Matt Aitken d9c9e80bc4 Changed "Worker" to "Version" in the CLI dev command key 2024-03-28 12:13:58 +00:00
Matt Aitken d39932ebf7 Changed the throttle so the function fires at the end of the period, not immediately when first called 2024-03-28 12:05:48 +00:00
Matt Aitken 9bcb8cb42a Ignore the DEBUG env var when deploying 2024-03-28 11:28:34 +00:00
nicktrn 2374f8e8ac fix docs for shopify scopes 2024-03-28 09:57:04 +00:00
github-actions[bot] a22b5869e4 chore: Update version for release (beta) (#977)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-03-27 19:43:19 +00:00
Eric Allam f1571cbfab Fixed an issue where the trigger.dev package was not being built before publishing to npm 2024-03-27 19:39:18 +00:00
150 changed files with 1625 additions and 700 deletions
+8
View File
@@ -0,0 +1,8 @@
---
"@trigger.dev/sdk": patch
"@trigger.dev/core-apps": patch
"trigger.dev": patch
"@trigger.dev/core": patch
---
add machine config and secure zod connection
+5
View File
@@ -0,0 +1,5 @@
---
"trigger.dev": patch
---
Changed "Worker" to "Version" in the dev command key
+6
View File
@@ -0,0 +1,6 @@
---
"trigger.dev": patch
"@trigger.dev/core": patch
---
Handle string and non-stringifiable outputs like functions
+8 -1
View File
@@ -45,7 +45,14 @@
},
"changesets": [
"chilled-hornets-move",
"clean-pianos-listen",
"lemon-jobs-repair",
"sweet-lizards-press"
"light-bulldogs-press",
"many-ligers-pump",
"real-planets-stare",
"strange-ghosts-matter",
"stupid-bulldogs-applaud",
"sweet-lizards-press",
"tall-bees-wave"
]
}
+7
View File
@@ -0,0 +1,7 @@
---
"@trigger.dev/sdk": patch
"trigger.dev": patch
"@trigger.dev/core": patch
---
Fixed incorrect span timings around checkpoints by implementing a precise wall clock that resets after restores
+5
View File
@@ -0,0 +1,5 @@
---
"trigger.dev": patch
---
Added DEBUG to the ignored env vars
+5
View File
@@ -0,0 +1,5 @@
---
"trigger.dev": patch
---
Fixed an issue where the trigger.dev package was not being built before publishing to npm
+7
View File
@@ -0,0 +1,7 @@
---
"@trigger.dev/sdk": patch
"trigger.dev": patch
"@trigger.dev/core": patch
---
Dynamically import superjson and fix some bundling issues
+10 -1
View File
@@ -63,4 +63,13 @@ COORDINATOR_SECRET=coordinator-secret # generate the actual secret with `openssl
# These are needed for the object store (for handling large payloads/outputs)
# OBJECT_STORE_BASE_URL="https://{bucket}.{accountId}.r2.cloudflarestorage.com"
# OBJECT_STORE_ACCESS_KEY_ID=
# OBJECT_STORE_SECRET_ACCESS_KEY=
# OBJECT_STORE_SECRET_ACCESS_KEY=
# RUNTIME_WAIT_THRESHOLD_IN_MS=10000
# These control the server-side internal telemetry
# INTERNAL_OTEL_TRACE_EXPORTER_URL=<URL to send traces to>
# INTERNAL_OTEL_TRACE_EXPORTER_AUTH_HEADER_NAME=<Header name for the auth token>
# INTERNAL_OTEL_TRACE_EXPORTER_AUTH_HEADER_VALUE=<Auth token value>
# INTERNAL_OTEL_TRACE_LOGGING_ENABLED=1
# INTERNAL_OTEL_TRACE_SAMPING_RATE=20 # this means 1/20 traces or 5% of traces will be sampled (sampled = recorded)
# INTERNAL_OTEL_TRACE_INSTRUMENT_PRISMA_ENABLED=0,
+2 -1
View File
@@ -1,3 +1,4 @@
HTTP_SERVER_PORT=8020
PLATFORM_ENABLED=true
PLATFORM_WS_PORT=3030
PLATFORM_WS_PORT=3030
SECURE_CONNECTION=false
+2
View File
@@ -26,6 +26,7 @@ const PLATFORM_ENABLED = ["1", "true"].includes(process.env.PLATFORM_ENABLED ??
const PLATFORM_HOST = process.env.PLATFORM_HOST || "127.0.0.1";
const PLATFORM_WS_PORT = process.env.PLATFORM_WS_PORT || 3030;
const PLATFORM_SECRET = process.env.PLATFORM_SECRET || "coordinator-secret";
const SECURE_CONNECTION = ["1", "true"].includes(process.env.SECURE_CONNECTION ?? "false");
const logger = new SimpleLogger(`[${NODE_NAME}]`);
@@ -365,6 +366,7 @@ class TaskCoordinator {
namespace: "coordinator",
host: PLATFORM_HOST,
port: Number(PLATFORM_WS_PORT),
secure: SECURE_CONNECTION,
clientMessages: CoordinatorToPlatformMessages,
serverMessages: PlatformToCoordinatorMessages,
authToken: PLATFORM_SECRET,
+1
View File
@@ -2,6 +2,7 @@ HTTP_SERVER_PORT=8050
PLATFORM_WS_PORT=3030
PLATFORM_SECRET=provider-secret
SECURE_CONNECTION=false
# Use this if you are on macOS
# COORDINATOR_HOST="host.docker.internal"
+32 -13
View File
@@ -8,6 +8,7 @@ import {
TaskOperationsIndexOptions,
} from "@trigger.dev/core-apps";
import { setTimeout } from "node:timers/promises";
import { PostStartCauses, PreStopCauses } from "@trigger.dev/core/v3";
const MACHINE_NAME = process.env.MACHINE_NAME || "local";
const COORDINATOR_PORT = process.env.COORDINATOR_PORT || 8020;
@@ -190,6 +191,9 @@ class DockerTaskOperations implements TaskOperations {
async delete(opts: { runId: string }) {
await this.#initialize();
const containerName = this.#getRunContainerName(opts.runId);
await this.#sendPreStop(containerName);
logger.log("noop: delete");
}
@@ -208,6 +212,26 @@ class DockerTaskOperations implements TaskOperations {
}
async #sendPostStart(containerName: string): Promise<void> {
try {
const port = await this.#getHttpServerPort(containerName);
logger.debug(await this.#runLifecycleCommand(containerName, port, "postStart", "restore"));
} catch (error) {
logger.error("postStart error", { error });
throw new Error("postStart command failed");
}
}
async #sendPreStop(containerName: string): Promise<void> {
try {
const port = await this.#getHttpServerPort(containerName);
logger.debug(await this.#runLifecycleCommand(containerName, port, "preStop", "terminate"));
} catch (error) {
logger.error("preStop error", { error });
throw new Error("preStop command failed");
}
}
async #getHttpServerPort(containerName: string): Promise<number> {
// We first get the correct port, which is random during dev as we run with host networking and need to avoid clashes
// FIXME: Skip this in prod
const logs = logger.debug(await $`docker logs ${containerName}`);
@@ -219,19 +243,14 @@ class DockerTaskOperations implements TaskOperations {
throw new Error("failed to extract port from logs");
}
try {
logger.debug(await this.#runLifecycleCommand(containerName, port, "postStart", "restore"));
} catch (error) {
logger.error("postStart error", { error });
throw new Error("postStart command failed");
}
return port;
}
async #runLifecycleCommand(
async #runLifecycleCommand<THookType extends "postStart" | "preStop">(
containerName: string,
port: number,
type: "postStart" | "preStop",
cause: "index" | "create" | "restore",
type: THookType,
cause: THookType extends "postStart" ? PostStartCauses : PreStopCauses,
retryCount = 0
): Promise<ExecaChildProcess> {
try {
@@ -244,15 +263,15 @@ class DockerTaskOperations implements TaskOperations {
`127.0.0.1:${port}/${type}?cause=${cause}`,
]);
} catch (error: any) {
if (retryCount < 6) {
logger.debug("retriable postStart error", { retryCount, message: error?.message });
if (type === "postStart" && retryCount < 6) {
logger.debug(`retriable ${type} error`, { retryCount, message: error?.message });
await setTimeout(exponentialBackoff(retryCount + 1, 2, 50, 1150, 50));
return this.#runLifecycleCommand(containerName, port, type, cause, retryCount + 1);
}
logger.error("final postStart error", { message: error?.message });
throw new Error(`postStart command failed after ${retryCount - 1} retries`);
logger.error(`final ${type} error`, { message: error?.message });
throw new Error(`${type} command failed after ${retryCount - 1} retries`);
}
}
}
+1
View File
@@ -2,6 +2,7 @@ HTTP_SERVER_PORT=8060
PLATFORM_WS_PORT=3030
PLATFORM_SECRET=provider-secret
SECURE_CONNECTION=false
# Use this if you are on macOS
# COORDINATOR_HOST="host.docker.internal"
+70 -9
View File
@@ -7,6 +7,7 @@ import {
TaskOperationsIndexOptions,
TaskOperationsRestoreOptions,
} from "@trigger.dev/core-apps";
import { Machine, PostStartCauses, PreStopCauses, EnvironmentType } from "@trigger.dev/core/v3";
import { randomUUID } from "crypto";
const RUNTIME_ENV = process.env.KUBERNETES_PORT ? "kubernetes" : "local";
@@ -55,6 +56,12 @@ class KubernetesTaskOperations implements TaskOperations {
metadata: {
labels: {
app: "task-index",
"app.kubernetes.io/part-of": "trigger-worker",
"app.kubernetes.io/component": "index",
env: opts.envId,
envtype: this.#envTypeToLabelValue(opts.envType),
org: opts.orgId,
project: opts.projectId,
},
},
spec: {
@@ -64,6 +71,9 @@ class KubernetesTaskOperations implements TaskOperations {
name: "registry-trigger",
},
],
nodeSelector: {
nodetype: "worker",
},
containers: [
{
name: this.#getIndexContainerName(opts.shortCode),
@@ -79,6 +89,13 @@ class KubernetesTaskOperations implements TaskOperations {
// memory: "50Mi",
// },
// },
lifecycle: {
preStop: {
exec: {
command: this.#getLifecycleCommand("preStop", "terminate"),
},
},
},
env: [
{
name: "DEBUG",
@@ -151,6 +168,13 @@ class KubernetesTaskOperations implements TaskOperations {
namespace: this.#namespace.metadata.name,
labels: {
app: "task-run",
"app.kubernetes.io/part-of": "trigger-worker",
"app.kubernetes.io/component": "create",
env: opts.envId,
envtype: this.#envTypeToLabelValue(opts.envType),
org: opts.orgId,
project: opts.projectId,
run: opts.runId,
},
},
spec: {
@@ -160,6 +184,9 @@ class KubernetesTaskOperations implements TaskOperations {
name: "registry-trigger",
},
],
nodeSelector: {
nodetype: "worker",
},
containers: [
{
name: this.#getRunContainerName(opts.runId),
@@ -169,9 +196,9 @@ class KubernetesTaskOperations implements TaskOperations {
containerPort: 8000,
},
],
// resources: {
// limits: opts.machine,
// },
resources: {
limits: this.#getResourcesFromMachineConfig(opts.machine),
},
lifecycle: {
postStart: {
exec: {
@@ -180,7 +207,7 @@ class KubernetesTaskOperations implements TaskOperations {
},
preStop: {
exec: {
command: this.#getLifecycleCommand("preStop", "create"),
command: this.#getLifecycleCommand("preStop", "terminate"),
},
},
},
@@ -262,6 +289,14 @@ class KubernetesTaskOperations implements TaskOperations {
namespace: this.#namespace.metadata.name,
labels: {
app: "task-run",
"app.kubernetes.io/part-of": "trigger-worker",
"app.kubernetes.io/component": "restore",
env: opts.envId,
envtype: this.#envTypeToLabelValue(opts.envType),
org: opts.orgId,
project: opts.projectId,
run: opts.runId,
checkpoint: opts.checkpointId,
},
},
spec: {
@@ -271,6 +306,9 @@ class KubernetesTaskOperations implements TaskOperations {
name: "registry-trigger",
},
],
nodeSelector: {
nodetype: "worker",
},
initContainers: [
{
name: "pull-base-image",
@@ -309,9 +347,9 @@ class KubernetesTaskOperations implements TaskOperations {
containerPort: 8000,
},
],
// resources: {
// limits: opts.machine,
// },
resources: {
limits: this.#getResourcesFromMachineConfig(opts.machine),
},
lifecycle: {
postStart: {
exec: {
@@ -320,7 +358,7 @@ class KubernetesTaskOperations implements TaskOperations {
},
preStop: {
exec: {
command: this.#getLifecycleCommand("preStop", "restore"),
command: this.#getLifecycleCommand("preStop", "terminate"),
},
},
},
@@ -355,7 +393,30 @@ class KubernetesTaskOperations implements TaskOperations {
await this.#getPod(opts.runId, this.#namespace);
}
#getLifecycleCommand(type: "postStart" | "preStop", cause: "index" | "create" | "restore") {
#envTypeToLabelValue(type: EnvironmentType) {
switch (type) {
case "PRODUCTION":
return "prod";
case "STAGING":
return "stg";
case "DEVELOPMENT":
return "dev";
case "PREVIEW":
return "preview";
}
}
#getResourcesFromMachineConfig(config: Machine) {
return {
cpu: `${config.cpu}`,
memory: `${config.memory}G`,
};
}
#getLifecycleCommand<THookType extends "postStart" | "preStop">(
type: THookType,
cause: THookType extends "postStart" ? PostStartCauses : PreStopCauses
) {
return ["/bin/sh", "-c", `sleep 1; wget -q -O- 127.0.0.1:8000/${type}?cause=${cause}`];
}
@@ -264,7 +264,7 @@ export function SideMenu({ user, project, organization, organizations }: SideMen
<SideMenuItem
name="Documentation (v3)"
icon="docs"
to="https://trigger.dev/docs"
to="https://trigger.dev/docs/v3"
data-action="documentation"
target="_blank"
/>
@@ -556,7 +556,7 @@ function V3ProjectSideMenu({
data-action="test"
/>
<SideMenuItem
name="API Keys"
name="API keys"
icon={KeyIcon}
iconColor="text-amber-500"
to={v3ApiKeysPath(organization, project)}
+4 -4
View File
@@ -14,9 +14,9 @@ import {
OperatingSystemContextProvider,
OperatingSystemPlatform,
} from "./components/primitives/OperatingSystemProvider";
import { env } from "./env.server";
import { getSharedSqsEventConsumer } from "./services/events/sqsEventConsumer";
import { singleton } from "./utils/singleton";
import { logger } from "./services/logger.server";
const ABORT_DELAY = 30000;
@@ -178,7 +178,7 @@ function logError(error: unknown, request?: Request) {
const sqsEventConsumer = singleton("sqsEventConsumer", getSharedSqsEventConsumer);
export { wss } from "./v3/handleWebsockets.server";
export { socketIo } from "./v3/handleSocketIo.server";
export { registryProxy } from "./v3/registryProxy.server";
export { apiRateLimiter } from "./services/apiRateLimit.server";
export { socketIo } from "./v3/handleSocketIo.server";
export { wss } from "./v3/handleWebsockets.server";
export { registryProxy } from "./v3/registryProxy.server";
+23 -3
View File
@@ -85,8 +85,6 @@ const EnvironmentSchema = z.object({
//v3
V3_ENABLED: z.string().default("false"),
OTLP_EXPORTER_TRACES_URL: z.string().optional(),
LOG_TELEMETRY: z.string().default("true"),
IMAGE_REGISTRY: z.string().default("docker.io"),
IMAGE_REPO: z.string().default("task"),
PROVIDER_SECRET: z.string().default("provider-secret"),
@@ -97,13 +95,35 @@ const EnvironmentSchema = z.object({
CONTAINER_REGISTRY_USERNAME: z.string().optional(),
CONTAINER_REGISTRY_PASSWORD: z.string().optional(),
DEPLOY_REGISTRY_HOST: z.string().optional(),
DEV_OTEL_EXPORTER_OTLP_ENDPOINT: z.string().optional(),
OBJECT_STORE_BASE_URL: z.string().optional(),
OBJECT_STORE_ACCESS_KEY_ID: z.string().optional(),
OBJECT_STORE_SECRET_ACCESS_KEY: z.string().optional(),
EVENTS_BATCH_SIZE: z.coerce.number().int().default(100),
EVENTS_BATCH_INTERVAL: z.coerce.number().int().default(1000),
EVENTS_DEFAULT_LOG_RETENTION: z.coerce.number().int().default(7),
// Development OTEL environment variables
DEV_OTEL_EXPORTER_OTLP_ENDPOINT: z.string().optional(),
// If this is set to 1, then the below variables are used to configure the batch processor for spans and logs
DEV_OTEL_BATCH_PROCESSING_ENABLED: z.string().default("0"),
DEV_OTEL_SPAN_MAX_EXPORT_BATCH_SIZE: z.string().default("64"),
DEV_OTEL_SPAN_SCHEDULED_DELAY_MILLIS: z.string().default("200"),
DEV_OTEL_SPAN_EXPORT_TIMEOUT_MILLIS: z.string().default("30000"),
DEV_OTEL_SPAN_MAX_QUEUE_SIZE: z.string().default("512"),
DEV_OTEL_LOG_MAX_EXPORT_BATCH_SIZE: z.string().default("64"),
DEV_OTEL_LOG_SCHEDULED_DELAY_MILLIS: z.string().default("200"),
DEV_OTEL_LOG_EXPORT_TIMEOUT_MILLIS: z.string().default("30000"),
DEV_OTEL_LOG_MAX_QUEUE_SIZE: z.string().default("512"),
RUNTIME_WAIT_THRESHOLD_IN_MS: z.coerce.number().int().default(30000),
// Internal OTEL environment variables
INTERNAL_OTEL_TRACE_EXPORTER_URL: z.string().optional(),
INTERNAL_OTEL_TRACE_EXPORTER_AUTH_HEADER_NAME: z.string().optional(),
INTERNAL_OTEL_TRACE_EXPORTER_AUTH_HEADER_VALUE: z.string().optional(),
INTERNAL_OTEL_TRACE_LOGGING_ENABLED: z.string().default("1"),
// this means 1/20 traces or 5% of traces will be sampled (sampled = recorded)
INTERNAL_OTEL_TRACE_SAMPING_RATE: z.string().default("20"),
INTERNAL_OTEL_TRACE_INSTRUMENT_PRISMA_ENABLED: z.string().default("0"),
});
export type Environment = z.infer<typeof EnvironmentSchema>;
@@ -43,14 +43,14 @@ export class SpanPresenter {
span.outputType === "application/store"
? `/resources/packets/${span.environmentId}/${span.output}`
: typeof span.output !== "undefined" && span.output !== null
? prettyPrintPacket(span.output, span.outputType ?? undefined)
? await prettyPrintPacket(span.output, span.outputType ?? undefined)
: undefined;
const payload =
span.payloadType === "application/store"
? `/resources/packets/${span.environmentId}/${span.payload}`
: typeof span.payload !== "undefined" && span.payload !== null
? prettyPrintPacket(span.payload, span.payloadType ?? undefined)
? await prettyPrintPacket(span.payload, span.payloadType ?? undefined)
: undefined;
return {
@@ -69,7 +69,8 @@ export class TestTaskPresenter {
ON
tr."taskIdentifier" = bwt.slug
WHERE
bwt."friendlyId" = ${taskFriendlyId}
bwt."friendlyId" = ${taskFriendlyId} AND
tr."runtimeEnvironmentId" = ${task.runtimeEnvironment.id}
ORDER BY
tr."createdAt" DESC
LIMIT 5
@@ -19,6 +19,7 @@ import {
TableHeaderCell,
TableRow,
} from "~/components/primitives/Table";
import { TextLink } from "~/components/primitives/TextLink";
import { useProject } from "~/hooks/useProject";
import { ApiKeysPresenter } from "~/presenters/v3/ApiKeysPresenter.server";
import { requireUserId } from "~/services/session.server";
@@ -55,12 +56,12 @@ export default function Page() {
return (
<PageContainer>
<NavBar>
<PageTitle title="API Keys" />
<PageTitle title="API keys" />
<PageAccessories>
<LinkButton
variant={"minimal/small"}
LeadingIcon={BookOpenIcon}
to={docsPath("/documentation/concepts/environments-endpoints#environments")}
to={docsPath("/v3/apikeys")}
>
API keys docs
</LinkButton>
@@ -68,9 +69,10 @@ export default function Page() {
</NavBar>
<PageBody>
<div className={cn("h-full")}>
<Header3 spacing>Server API keys</Header3>
<Header3 spacing>Secret keys</Header3>
<Paragraph variant="small" spacing>
Server API keys should be used on your server they give full API access.
Secret keys should be used on your server they give full API access and allow you to{" "}
<TextLink to={docsPath("v3/triggering")}>trigger tasks</TextLink> from your backend.
</Paragraph>
<Header3 spacing>Public API keys</Header3>
<Paragraph variant="small" spacing>
@@ -81,7 +83,7 @@ export default function Page() {
<TableHeader>
<TableRow>
<TableHeaderCell>Environment</TableHeaderCell>
<TableHeaderCell>Server API key</TableHeaderCell>
<TableHeaderCell>Secret key</TableHeaderCell>
<TableHeaderCell>Public API key</TableHeaderCell>
<TableHeaderCell>Keys generated</TableHeaderCell>
<TableHeaderCell>Latest version</TableHeaderCell>
@@ -167,7 +167,7 @@ export default function Page() {
<PageAccessories>
<LinkButton
LeadingIcon={BookOpenIcon}
to={docsPath("/documentation/concepts/environments-endpoints#environments")}
to={docsPath("v3/deploy-environment-variables")}
variant="minimal/small"
>
Environment variables docs
@@ -222,19 +222,25 @@ function PacketDisplay({
dataType: string;
title: string;
}) {
if (dataType === "application/store") {
return (
<div className="flex flex-col">
<Paragraph variant="base/bright" className="w-full border-b border-grid-dimmed py-2.5">
{title}
</Paragraph>
<LinkButton LeadingIcon={CloudArrowDownIcon} to={data} variant="tertiary/medium" download>
Download
</LinkButton>
</div>
);
} else {
return <CodeBlock rowTitle={title} code={data} maxLines={20} />;
switch (dataType) {
case "application/store": {
return (
<div className="flex flex-col">
<Paragraph variant="base/bright" className="w-full border-b border-grid-dimmed py-2.5">
{title}
</Paragraph>
<LinkButton LeadingIcon={CloudArrowDownIcon} to={data} variant="tertiary/medium" download>
Download
</LinkButton>
</div>
);
}
case "text/plain": {
return <CodeBlock language="markdown" rowTitle={title} code={data} maxLines={20} />;
}
default: {
return <CodeBlock language="json" rowTitle={title} code={data} maxLines={20} />;
}
}
}
+8 -8
View File
@@ -1,20 +1,20 @@
//From: https://kettanaito.com/blog/debounce-vs-throttle
/** A very simple throttle. Will execute the function every Xms and discard any other calls during that period. */
/** A very simple throttle. Will execute the function at the end of each period and discard any other calls during that period. */
export function throttle(
func: (...args: any[]) => void,
duration: number
durationMs: number
): (...args: any[]) => void {
let shouldWait = false;
let isPrimedToFire = false;
return (...args: any[]) => {
if (!shouldWait) {
func(...args);
shouldWait = true;
if (!isPrimedToFire) {
isPrimedToFire = true;
setTimeout(() => {
shouldWait = false;
}, duration);
func(...args);
isPrimedToFire = false;
}, durationMs);
}
};
}
@@ -30,7 +30,7 @@ function parseSecretKey(key: string) {
const SecretValue = z.object({ secret: z.string() });
export class EnvironmentVariablesRepository implements Repository {
constructor(private prismaClient: PrismaClient = prisma) { }
constructor(private prismaClient: PrismaClient = prisma) {}
async create(
projectId: string,
@@ -419,8 +419,49 @@ export class EnvironmentVariablesRepository implements Repository {
{
key: "OTEL_EXPORTER_OTLP_ENDPOINT",
value: env.DEV_OTEL_EXPORTER_OTLP_ENDPOINT ?? env.APP_ORIGIN,
}
];
},
].concat(
env.DEV_OTEL_BATCH_PROCESSING_ENABLED === "1"
? [
{
key: "OTEL_BATCH_PROCESSING_ENABLED",
value: "1",
},
{
key: "OTEL_SPAN_MAX_EXPORT_BATCH_SIZE",
value: env.DEV_OTEL_SPAN_MAX_EXPORT_BATCH_SIZE,
},
{
key: "OTEL_SPAN_SCHEDULED_DELAY_MILLIS",
value: env.DEV_OTEL_SPAN_SCHEDULED_DELAY_MILLIS,
},
{
key: "OTEL_SPAN_EXPORT_TIMEOUT_MILLIS",
value: env.DEV_OTEL_SPAN_EXPORT_TIMEOUT_MILLIS,
},
{
key: "OTEL_SPAN_MAX_QUEUE_SIZE",
value: env.DEV_OTEL_SPAN_MAX_QUEUE_SIZE,
},
{
key: "OTEL_LOG_MAX_EXPORT_BATCH_SIZE",
value: env.DEV_OTEL_LOG_MAX_EXPORT_BATCH_SIZE,
},
{
key: "OTEL_LOG_SCHEDULED_DELAY_MILLIS",
value: env.DEV_OTEL_LOG_SCHEDULED_DELAY_MILLIS,
},
{
key: "OTEL_LOG_EXPORT_TIMEOUT_MILLIS",
value: env.DEV_OTEL_LOG_EXPORT_TIMEOUT_MILLIS,
},
{
key: "OTEL_LOG_MAX_QUEUE_SIZE",
value: env.DEV_OTEL_LOG_MAX_QUEUE_SIZE,
},
]
: []
);
}
return [
@@ -432,6 +473,10 @@ export class EnvironmentVariablesRepository implements Repository {
key: "TRIGGER_API_URL",
value: env.APP_ORIGIN,
},
{
key: "TRIGGER_RUNTIME_WAIT_THRESHOLD_IN_MS",
value: String(env.RUNTIME_WAIT_THRESHOLD_IN_MS),
},
];
}
+5 -4
View File
@@ -10,7 +10,7 @@ import {
SpanMessagingEvent,
TaskEventStyle,
correctErrorStackTrace,
createPackageAttributesAsJson,
createPacketAttributesAsJson,
flattenAttributes,
isExceptionSpanEvent,
omit,
@@ -188,7 +188,7 @@ export class EventRepository {
const event = events[0];
const output = options?.attributes.output
? createPackageAttributesAsJson(
? await createPacketAttributesAsJson(
options?.attributes.output,
options?.attributes.outputType ?? "application/json"
)
@@ -213,8 +213,9 @@ export class EventRepository {
style: event.style as Attributes,
output: output,
outputType:
options?.attributes.outputType === "application/store"
? "application/store"
options?.attributes.outputType === "application/store" ||
options?.attributes.outputType === "text/plain"
? options?.attributes.outputType
: "application/json",
payload: event.payload as Attributes,
payloadType: event.payloadType,
-8
View File
@@ -591,14 +591,6 @@ export class MarQS {
concurrencyLimitKey: string;
currentConcurrencyKey: string;
}) {
logger.debug("Calling dequeueMessage", {
messageQueue,
parentQueue,
visibilityQueue,
concurrencyLimitKey,
currentConcurrencyKey,
});
const result = await this.redis.dequeueMessage(
messageQueue,
parentQueue,
@@ -1,5 +1,6 @@
import { Context, ROOT_CONTEXT, Span, SpanKind, context, trace } from "@opentelemetry/api";
import {
Machine,
ProdTaskRunExecution,
ProdTaskRunExecutionPayload,
TaskRunError,
@@ -438,10 +439,27 @@ export class SharedQueueConsumer {
queueId: queue.id,
runtimeEnvironmentId: environment.id,
},
include: {
backgroundWorkerTask: true,
},
});
const isRetry = taskRunAttempt.number > 1;
const { machineConfig } = taskRunAttempt.backgroundWorkerTask;
const machine = Machine.safeParse(machineConfig ?? {});
if (!machine.success) {
logger.error("Failed to parse machine config", {
queueMessage: message.data,
messageId: message.messageId,
attemptId: taskRunAttempt.id,
machineConfig,
});
await this.#ackAndDoMoreWork(message.messageId);
return;
}
try {
if (messageBody.data.checkpointEventId) {
const restoreService = new RestoreCheckpointService();
@@ -470,11 +488,16 @@ export class SharedQueueConsumer {
backgroundWorkerId: deployment.worker.friendlyId,
data: {
type: "SCHEDULE_ATTEMPT",
id: taskRunAttempt.id,
image: deployment.imageReference,
envId: environment.id,
runId: taskRunAttempt.taskRunId,
version: deployment.version,
machine: machine.data,
// identifiers
id: taskRunAttempt.id,
envId: environment.id,
envType: environment.type,
orgId: environment.organizationId,
projectId: environment.projectId,
runId: taskRunAttempt.taskRunId,
},
});
}
+26 -6
View File
@@ -259,6 +259,18 @@ export class RegistryProxy {
proxyRes.pipe(response, { end: true });
});
request.on("close", () => {
logger.debug("Client closed the connection");
proxyReq.destroy();
cleanupTempFile();
});
request.on("abort", () => {
logger.debug("Client aborted the connection");
proxyReq.destroy(); // Abort the proxied request
cleanupTempFile(); // Clean up the temporary file if necessary
});
if (tempFilePath) {
const readStream = createReadStream(tempFilePath);
@@ -427,14 +439,22 @@ function initializeProxy() {
});
}
async function streamRequestBodyToTempFile(request: IncomingMessage): Promise<string> {
const tempDir = await mkdtemp(`${tmpdir()}/`);
const tempFilePath = `${tempDir}/requestBody.tmp`;
const writeStream = createWriteStream(tempFilePath);
async function streamRequestBodyToTempFile(request: IncomingMessage): Promise<string | undefined> {
try {
const tempDir = await mkdtemp(`${tmpdir()}/`);
const tempFilePath = `${tempDir}/requestBody.tmp`;
const writeStream = createWriteStream(tempFilePath);
await pipeline(request, writeStream);
await pipeline(request, writeStream);
return tempFilePath;
return tempFilePath;
} catch (error) {
logger.error("Failed to stream request body to temp file", {
error: error instanceof Error ? error.message : error,
});
return;
}
}
type DockerImageParts = {
@@ -105,7 +105,7 @@ export class CompleteAttemptService extends BaseService {
attributes: {
isError: false,
output:
completion.outputType === "application/store"
completion.outputType === "application/store" || completion.outputType === "text/plain"
? completion.output
: completion.output
? (safeJsonParse(completion.output) as Attributes)
@@ -101,6 +101,7 @@ export async function createBackgroundTasks(
exportName: task.exportName,
retryConfig: task.retry,
queueConfig: task.queue,
machineConfig: task.machine,
},
});
@@ -49,9 +49,13 @@ export class IndexDeploymentService extends BaseService {
version: "v1",
shortCode: deployment.shortCode,
imageTag: deployment.imageReference,
envId: deployment.environmentId,
apiKey: deployment.environment.apiKey,
apiUrl: env.APP_ORIGIN,
// identifiers
envId: deployment.environmentId,
envType: deployment.environment.type,
projectId: deployment.projectId,
orgId: deployment.environment.organizationId,
});
logger.debug("Index ACK received", { responses });
@@ -3,6 +3,7 @@ import { logger } from "~/services/logger.server";
import { socketIo } from "../handleSocketIo.server";
import { CreateCheckpointRestoreEventService } from "./createCheckpointRestoreEvent.server";
import { BaseService } from "./baseService.server";
import { Machine } from "@trigger.dev/core/v3";
const RESTORABLE_RUN_STATUSES: TaskRunStatus[] = ["WAITING_TO_RESUME"];
const RESTORABLE_ATTEMPT_STATUSES: TaskRunAttemptStatus[] = ["PAUSED"];
@@ -30,8 +31,14 @@ export class RestoreCheckpointService extends BaseService {
attempt: {
select: {
status: true,
backgroundWorkerTask: {
select: {
machineConfig: true,
},
},
},
},
runtimeEnvironment: true,
},
},
},
@@ -63,17 +70,34 @@ export class RestoreCheckpointService extends BaseService {
return;
}
const { machineConfig } = checkpoint.attempt.backgroundWorkerTask;
const machine = Machine.safeParse(machineConfig ?? {});
if (!machine.success) {
logger.error("Failed to parse machine config", {
attemptId: checkpoint.attemptId,
machineConfig: checkpoint.attempt.backgroundWorkerTask.machineConfig,
});
return;
}
const eventService = new CreateCheckpointRestoreEventService(this._prisma);
await eventService.restore({ checkpointId: checkpoint.id });
socketIo.providerNamespace.emit("RESTORE", {
version: "v1",
checkpointId: checkpoint.id,
runId: checkpoint.runId,
type: checkpoint.type,
location: checkpoint.location,
reason: checkpoint.reason ?? undefined,
imageRef: checkpoint.imageRef,
machine: machine.data,
// identifiers
checkpointId: checkpoint.id,
envId: checkpoint.runtimeEnvironment.id,
envType: checkpoint.runtimeEnvironment.type,
orgId: checkpoint.runtimeEnvironment.organizationId,
projectId: checkpoint.runtimeEnvironment.projectId,
runId: checkpoint.runId,
});
return checkpoint;
+40 -20
View File
@@ -9,7 +9,7 @@ import {
trace,
} from "@opentelemetry/api";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { registerInstrumentations } from "@opentelemetry/instrumentation";
import { InstrumentationOption, registerInstrumentations } from "@opentelemetry/instrumentation";
import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
import { Resource } from "@opentelemetry/resources";
@@ -23,12 +23,13 @@ import {
TraceIdRatioBasedSampler,
} from "@opentelemetry/sdk-trace-base";
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
import { SEMRESATTRS_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
import { PrismaInstrumentation } from "@prisma/instrumentation";
import { env } from "~/env.server";
import { AuthenticatedEnvironment } from "~/services/apiAuth.server";
import { singleton } from "~/utils/singleton";
import { LoggerSpanExporter } from "./telemetry/loggerExporter.server";
class CustomWebappSampler implements Sampler {
constructor(private readonly _baseSampler: Sampler) {}
@@ -44,10 +45,7 @@ class CustomWebappSampler implements Sampler {
const parentContext = trace.getSpanContext(context);
// Exclude Prisma spans (adjust this logic as needed for your use case)
if (
!parentContext &&
((attributes && attributes["model"] && attributes["method"]) || name.includes("prisma"))
) {
if (!parentContext && name.includes("prisma")) {
return { decision: SamplingDecision.NOT_RECORD };
}
@@ -65,29 +63,46 @@ export const tracer = singleton("tracer", getTracer);
function getTracer() {
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.ERROR);
const samplingRate = 1.0 / Math.max(parseInt(env.INTERNAL_OTEL_TRACE_SAMPING_RATE, 10), 1);
const provider = new NodeTracerProvider({
forceFlushTimeoutMillis: 500,
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: "trigger.dev",
[SEMRESATTRS_SERVICE_NAME]: "trigger.dev",
}),
sampler: new ParentBasedSampler({
root: new CustomWebappSampler(
new TraceIdRatioBasedSampler(env.APP_ENV === "development" ? 1.0 : 0.05)
), // 5% sampling
root: new CustomWebappSampler(new TraceIdRatioBasedSampler(samplingRate)), // 5% sampling
}), // 5% sampling
});
if (env.OTLP_EXPORTER_TRACES_URL) {
if (env.INTERNAL_OTEL_TRACE_EXPORTER_URL) {
const exporter = new OTLPTraceExporter({
url: env.OTLP_EXPORTER_TRACES_URL,
url: env.INTERNAL_OTEL_TRACE_EXPORTER_URL,
timeoutMillis: 1000,
headers:
env.INTERNAL_OTEL_TRACE_EXPORTER_AUTH_HEADER_NAME &&
env.INTERNAL_OTEL_TRACE_EXPORTER_AUTH_HEADER_VALUE
? {
[env.INTERNAL_OTEL_TRACE_EXPORTER_AUTH_HEADER_NAME]:
env.INTERNAL_OTEL_TRACE_EXPORTER_AUTH_HEADER_VALUE,
}
: undefined,
});
provider.addSpanProcessor(new BatchSpanProcessor(exporter));
provider.addSpanProcessor(
new BatchSpanProcessor(exporter, {
maxExportBatchSize: 512,
scheduledDelayMillis: 200,
exportTimeoutMillis: 30000,
maxQueueSize: 2048,
})
);
console.log(` Tracer: OTLP exporter enabled to ${env.OTLP_EXPORTER_TRACES_URL}`);
console.log(`🔦 Tracer: OTLP exporter enabled to ${env.INTERNAL_OTEL_TRACE_EXPORTER_URL}`);
} else {
if (env.LOG_TELEMETRY === "true") {
if (env.INTERNAL_OTEL_TRACE_LOGGING_ENABLED === "1") {
console.log(`🔦 Tracer: Logger exporter enabled`);
const loggerExporter = new LoggerSpanExporter();
provider.addSpanProcessor(new SimpleSpanProcessor(loggerExporter));
@@ -96,13 +111,18 @@ function getTracer() {
provider.register();
let instrumentations: InstrumentationOption[] = [
new HttpInstrumentation(),
new ExpressInstrumentation(),
];
if (env.INTERNAL_OTEL_TRACE_INSTRUMENT_PRISMA_ENABLED === "1") {
instrumentations.push(new PrismaInstrumentation());
}
registerInstrumentations({
tracerProvider: provider,
instrumentations: [
new HttpInstrumentation(),
new ExpressInstrumentation(),
new PrismaInstrumentation(),
],
instrumentations,
});
return provider.getTracer("trigger.dev", "3.0.0.dp.1");
Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

+3 -1
View File
@@ -63,7 +63,9 @@ You can use Personal Access Tokens to authenticate with Shopify and get started
To create the tokens on Shopify, login and [follow the instructions](https://help.shopify.com/en/manual/apps/app-types/custom-apps#create-and-install-a-custom-app).
The [required scopes](https://shopify.dev/docs/api/usage/access-scopes#authenticated-access-scopes) depend on the tasks you wish to perform and which webhooks you intend to receive. Webhooks will generally need read access to the respective Shopify resource.
The [required scopes](https://shopify.dev/docs/api/usage/access-scopes#authenticated-access-scopes) depend on the tasks you wish to perform and which webhooks you intend to receive.
Webhooks will generally need read access to the respective Shopify resource at the very least. If the topic you subscribe to is triggered by an action that requires write access, e.g. `orders/create`, then write access is also required, e.g. `write_orders`.
Additionally, you will also have to provide your shop domain.
+1
View File
@@ -452,6 +452,7 @@
"v3/trigger-folder",
"v3/tasks-overview",
"v3/triggering",
"v3/apikeys",
{
"group": "Task types",
"pages": ["v3/tasks-regular", "v3/tasks-scheduled", "v3/tasks-zod", "v3/tasks-webhooks"]
+12
View File
@@ -0,0 +1,12 @@
---
title: "API keys"
description: "How to authenticate with Trigger.dev so you can trigger tasks."
---
### Authentication and your secret keys
When you [trigger a task](/v3/triggering) from your backend code, you need to set the `TRIGGER_SECRET_KEY` environment variable.
Each environment has its own secret key. You can find the value on the API keys page in the Trigger.dev dashboard:
![How to find your secret key](/images/v3/api-keys.png)
+1 -1
View File
@@ -18,7 +18,7 @@ We deploy your tasks and scale them up and down when they are triggered. So any
<Step title="Add your environment variables">
You can add values for your local dev environment, staging and prod. ![Environment variables
page](/images/v3/environment-variables-page.jpg){" "}
page](/images/v3/environment-variables-panel.jpg)
</Step>
</Steps>
+4
View File
@@ -23,6 +23,10 @@ You can trigger any task from your backend code, using either `trigger()` or `ba
Trigger.dev API key to the world.
</Note>
### Authentication
When you trigger a task from your backend code, you need to set the `TRIGGER_SECRET_KEY` environment variable. You can find the value on the API keys page in the Trigger.dev dashboard. [More info on API keys](/v3/apikeys).
### trigger()
Triggers a single run of a task with the payload you pass in, and any options you specify. It does NOT wait for the result, you cannot do that from outside a task.
+17
View File
@@ -1,5 +1,22 @@
# @trigger.dev/airtable
## 3.0.0-beta.2
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.2
- @trigger.dev/sdk@3.0.0-beta.2
## 3.0.0-beta.1
### Patch Changes
- Updated dependencies [b66d5525e]
- Updated dependencies [719c0a0b9]
- Updated dependencies [f93eae300]
- @trigger.dev/sdk@3.0.0-beta.1
- @trigger.dev/integration-kit@3.0.0-beta.1
## 3.0.0-beta.0
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/airtable",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"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.0",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.0",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.2",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.2",
"airtable": "^0.12.1",
"zod": "3.22.3"
},
+17
View File
@@ -1,5 +1,22 @@
# @trigger.dev/github
## 3.0.0-beta.2
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.2
- @trigger.dev/sdk@3.0.0-beta.2
## 3.0.0-beta.1
### Patch Changes
- Updated dependencies [b66d5525e]
- Updated dependencies [719c0a0b9]
- Updated dependencies [f93eae300]
- @trigger.dev/sdk@3.0.0-beta.1
- @trigger.dev/integration-kit@3.0.0-beta.1
## 3.0.0-beta.0
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/github",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"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.0",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.0",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.2",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.2",
"zod": "3.22.3"
},
"engines": {
+17
View File
@@ -1,5 +1,22 @@
# @trigger.dev/linear
## 3.0.0-beta.2
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.2
- @trigger.dev/sdk@3.0.0-beta.2
## 3.0.0-beta.1
### Patch Changes
- Updated dependencies [b66d5525e]
- Updated dependencies [719c0a0b9]
- Updated dependencies [f93eae300]
- @trigger.dev/sdk@3.0.0-beta.1
- @trigger.dev/integration-kit@3.0.0-beta.1
## 3.0.0-beta.0
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/linear",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"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.0",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.0",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.2",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.2",
"zod": "3.22.3"
},
"engines": {
+17
View File
@@ -1,5 +1,22 @@
# @trigger.dev/slack
## 3.0.0-beta.2
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.2
- @trigger.dev/sdk@3.0.0-beta.2
## 3.0.0-beta.1
### Patch Changes
- Updated dependencies [b66d5525e]
- Updated dependencies [719c0a0b9]
- Updated dependencies [f93eae300]
- @trigger.dev/sdk@3.0.0-beta.1
- @trigger.dev/integration-kit@3.0.0-beta.1
## 3.0.0-beta.0
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/openai",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"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.0",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.0"
"@trigger.dev/sdk": "workspace:^3.0.0-beta.2",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.2"
},
"engines": {
"node": ">=18.0.0"
+17
View File
@@ -1,5 +1,22 @@
# @trigger.dev/plain
## 3.0.0-beta.2
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.2
- @trigger.dev/sdk@3.0.0-beta.2
## 3.0.0-beta.1
### Patch Changes
- Updated dependencies [b66d5525e]
- Updated dependencies [719c0a0b9]
- Updated dependencies [f93eae300]
- @trigger.dev/sdk@3.0.0-beta.1
- @trigger.dev/integration-kit@3.0.0-beta.1
## 3.0.0-beta.0
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/plain",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"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.0",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.0",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.2",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.2",
"@team-plain/typescript-sdk": "^2.7.0"
},
"engines": {
+17
View File
@@ -1,5 +1,22 @@
# @trigger.dev/replicate
## 3.0.0-beta.2
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.2
- @trigger.dev/sdk@3.0.0-beta.2
## 3.0.0-beta.1
### Patch Changes
- Updated dependencies [b66d5525e]
- Updated dependencies [719c0a0b9]
- Updated dependencies [f93eae300]
- @trigger.dev/sdk@3.0.0-beta.1
- @trigger.dev/integration-kit@3.0.0-beta.1
## 3.0.0-beta.0
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/replicate",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"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.0",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.0",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.2",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.2",
"replicate": "^0.18.1",
"zod": "3.22.3"
},
+17
View File
@@ -1,5 +1,22 @@
# @trigger.dev/resend
## 3.0.0-beta.2
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.2
- @trigger.dev/sdk@3.0.0-beta.2
## 3.0.0-beta.1
### Patch Changes
- Updated dependencies [b66d5525e]
- Updated dependencies [719c0a0b9]
- Updated dependencies [f93eae300]
- @trigger.dev/sdk@3.0.0-beta.1
- @trigger.dev/integration-kit@3.0.0-beta.1
## 3.0.0-beta.0
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/resend",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"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.0",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.0",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.2",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.2",
"resend": "^2.1.0"
},
"engines": {
+17
View File
@@ -1,5 +1,22 @@
# @trigger.dev/sendgrid
## 3.0.0-beta.2
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.2
- @trigger.dev/sdk@3.0.0-beta.2
## 3.0.0-beta.1
### Patch Changes
- Updated dependencies [b66d5525e]
- Updated dependencies [719c0a0b9]
- Updated dependencies [f93eae300]
- @trigger.dev/sdk@3.0.0-beta.1
- @trigger.dev/integration-kit@3.0.0-beta.1
## 3.0.0-beta.0
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/sendgrid",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"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.0",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.0"
"@trigger.dev/sdk": "workspace:^3.0.0-beta.2",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.2"
},
"engines": {
"node": ">=16.8.0"
+17
View File
@@ -1,5 +1,22 @@
# @trigger.dev/shopify
## 3.0.0-beta.2
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.2
- @trigger.dev/sdk@3.0.0-beta.2
## 3.0.0-beta.1
### Patch Changes
- Updated dependencies [b66d5525e]
- Updated dependencies [719c0a0b9]
- Updated dependencies [f93eae300]
- @trigger.dev/sdk@3.0.0-beta.1
- @trigger.dev/integration-kit@3.0.0-beta.1
## 3.0.0-beta.0
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/shopify",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"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.0",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.0",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.2",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.2",
"zod": "3.22.3"
},
"engines": {
+15
View File
@@ -1,5 +1,20 @@
# @trigger.dev/slack
## 3.0.0-beta.2
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.2
## 3.0.0-beta.1
### Patch Changes
- Updated dependencies [b66d5525e]
- Updated dependencies [719c0a0b9]
- Updated dependencies [f93eae300]
- @trigger.dev/sdk@3.0.0-beta.1
## 3.0.0-beta.0
### Patch Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/slack",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"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.0",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.2",
"zod": "3.22.3"
},
"engines": {
+17
View File
@@ -1,5 +1,22 @@
# @trigger.dev/stripe
## 3.0.0-beta.2
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.2
- @trigger.dev/sdk@3.0.0-beta.2
## 3.0.0-beta.1
### Patch Changes
- Updated dependencies [b66d5525e]
- Updated dependencies [719c0a0b9]
- Updated dependencies [f93eae300]
- @trigger.dev/sdk@3.0.0-beta.1
- @trigger.dev/integration-kit@3.0.0-beta.1
## 3.0.0-beta.0
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/stripe",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"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.0",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.0",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.2",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.2",
"stripe": "^12.14.0",
"zod": "3.22.3"
},
+17
View File
@@ -1,5 +1,22 @@
# @trigger.dev/supabase
## 3.0.0-beta.2
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.2
- @trigger.dev/sdk@3.0.0-beta.2
## 3.0.0-beta.1
### Patch Changes
- Updated dependencies [b66d5525e]
- Updated dependencies [719c0a0b9]
- Updated dependencies [f93eae300]
- @trigger.dev/sdk@3.0.0-beta.1
- @trigger.dev/integration-kit@3.0.0-beta.1
## 3.0.0-beta.0
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/supabase",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"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.0",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.0",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.2",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.2",
"supabase-management-js": "^1.0.0",
"zod": "3.22.3"
},
+17
View File
@@ -1,5 +1,22 @@
# @trigger.dev/typeform
## 3.0.0-beta.2
### Patch Changes
- @trigger.dev/integration-kit@3.0.0-beta.2
- @trigger.dev/sdk@3.0.0-beta.2
## 3.0.0-beta.1
### Patch Changes
- Updated dependencies [b66d5525e]
- Updated dependencies [719c0a0b9]
- Updated dependencies [f93eae300]
- @trigger.dev/sdk@3.0.0-beta.1
- @trigger.dev/integration-kit@3.0.0-beta.1
## 3.0.0-beta.0
### Patch Changes
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/typeform",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"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.0",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.0",
"@trigger.dev/integration-kit": "workspace:^3.0.0-beta.2",
"@trigger.dev/sdk": "workspace:^3.0.0-beta.2",
"@typeform/api-client": "^1.8.0",
"zod": "3.22.3"
},
+1 -1
View File
@@ -38,7 +38,7 @@
"env:pull": "turbo run env:pull",
"changeset:add": "changeset",
"changeset:version": "changeset version",
"changeset:release": "pnpm run build --filter \"@trigger.dev/*\" && changeset publish",
"changeset:release": "pnpm run build --filter \"@trigger.dev/*\" --filter \"trigger.dev\" && changeset publish",
"changeset:beta": "changeset pre enter beta",
"changeset:normal": "changeset pre exit",
"clean:sourcemaps": "turbo run clean:sourcemaps",
+15
View File
@@ -1,5 +1,20 @@
# @trigger.dev/astro
## 3.0.0-beta.2
### Patch Changes
- @trigger.dev/sdk@3.0.0-beta.2
## 3.0.0-beta.1
### Patch Changes
- Updated dependencies [b66d5525e]
- Updated dependencies [719c0a0b9]
- Updated dependencies [f93eae300]
- @trigger.dev/sdk@3.0.0-beta.1
## 3.0.0-beta.0
### Patch Changes
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "@trigger.dev/astro",
"description": "An Astro-native integration for Trigger.dev background jobs platform",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"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.0"
"@trigger.dev/sdk": "workspace:^3.0.0-beta.2"
},
"devDependencies": {
"astro": "^3.0.12",
+28
View File
@@ -1,5 +1,33 @@
# trigger.dev
## 3.0.0-beta.3
### Patch Changes
- e3cf456c6: Handle string and non-stringifiable outputs like functions
- Updated dependencies [e3cf456c6]
- @trigger.dev/core@3.0.0-beta.2
## 3.0.0-beta.2
### Patch Changes
- b66d5525e: add machine config and secure zod connection
- d9c9e80bc: Changed "Worker" to "Version" in the dev command key
- 719c0a0b9: Fixed incorrect span timings around checkpoints by implementing a precise wall clock that resets after restores
- 9bcb8cb42: Added DEBUG to the ignored env vars
- f93eae300: Dynamically import superjson and fix some bundling issues
- Updated dependencies [b66d5525e]
- Updated dependencies [719c0a0b9]
- Updated dependencies [f93eae300]
- @trigger.dev/core@3.0.0-beta.1
## 3.0.0-beta.1
### Patch Changes
- f1571cbfa: Fixed an issue where the trigger.dev package was not being built before publishing to npm
## 3.0.0-beta.0
### Major Changes
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "trigger.dev",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.3",
"description": "A Command-Line Interface for Trigger.dev (v3) projects",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -89,7 +89,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.0",
"@trigger.dev/core": "workspace:^3.0.0-beta.2",
"@types/degit": "^2.8.3",
"chalk": "^5.2.0",
"chokidar": "^3.5.3",
+23 -4
View File
@@ -889,7 +889,14 @@ async function compileProject(
TRIGGER_API_URL: `"${config.triggerUrl}"`,
__PROJECT_CONFIG__: JSON.stringify(config),
},
plugins: [bundleDependenciesPlugin(config), workerSetupImportConfigPlugin(configPath)],
plugins: [
bundleDependenciesPlugin(
"workerFacade",
config.dependenciesToBundle,
config.tsconfigPath
),
workerSetupImportConfigPlugin(configPath),
],
});
if (result.errors.length > 0) {
@@ -927,15 +934,22 @@ async function compileProject(
write: false,
minify: false,
sourcemap: false,
packages: "external", // https://esbuild.github.io/api/#packages
logLevel: "error",
platform: "node",
packages: "external",
format: "cjs", // This is needed to support opentelemetry instrumentation that uses module patching
target: ["node18", "es2020"],
outdir: "out",
define: {
__PROJECT_CONFIG__: JSON.stringify(config),
},
plugins: [
bundleDependenciesPlugin(
"entryPoint.ts",
config.dependenciesToBundle,
config.tsconfigPath
),
],
});
if (entryPointResult.errors.length > 0) {
@@ -1003,6 +1017,11 @@ async function compileProject(
// Save the entryPoint outputFile to /tmp/dir/index.js
await writeFile(join(tempDir, "index.js"), entryPointOutputFile.text);
logger.debug("Getting the imports for the worker and entryPoint builds", {
workerImports: metaOutput.imports,
entryPointImports: entryPointMetaOutput.imports,
});
// Get all the required dependencies from the metaOutputs and save them to /tmp/dir/package.json
const allImports = [...metaOutput.imports, ...entryPointMetaOutput.imports];
@@ -1246,7 +1265,7 @@ async function gatherRequiredDependencies(
const dependencies: Record<string, string> = {};
for (const file of imports) {
if (file.kind !== "require-call" || !file.external) {
if ((file.kind !== "require-call" && file.kind !== "dynamic-import") || !file.external) {
continue;
}
@@ -1382,7 +1401,7 @@ async function findAllEnvironmentVariableReferencesInFile(filePath: string) {
return findAllEnvironmentVariableReferences(fileContents);
}
const IGNORED_ENV_VARS = ["NODE_ENV", "SHELL", "HOME", "PWD", "LOGNAME", "USER", "PATH"];
const IGNORED_ENV_VARS = ["NODE_ENV", "SHELL", "HOME", "PWD", "LOGNAME", "USER", "PATH", "DEBUG"];
function findAllEnvironmentVariableReferences(code: string): string[] {
const regex = /\bprocess\.env\.([a-zA-Z_][a-zA-Z0-9_]*)\b/g;
+22 -10
View File
@@ -26,7 +26,7 @@ import * as packageJson from "../../package.json";
import { CliApiClient } from "../apiClient";
import { CommonCommandOptions, commonOptions, wrapCommandAction } from "../cli/common.js";
import { bundleDependenciesPlugin, workerSetupImportConfigPlugin } from "../utilities/build";
import { chalkGrey, chalkPurple, chalkWorker } from "../utilities/cliOutput";
import { chalkError, chalkGrey, chalkPurple, chalkTask, chalkWorker } from "../utilities/cliOutput";
import { readConfig } from "../utilities/configFiles";
import { readJSONFile } from "../utilities/fileSystem";
import { printDevBanner, printStandloneInitialBanner } from "../utilities/initialBanner.js";
@@ -77,9 +77,13 @@ export async function devCommand(dir: string, options: DevCommandOptions) {
if (!authorization.ok) {
if (authorization.error === "fetch failed") {
logger.error("Fetch failed. Platform down?");
logger.log(
`${chalkError(
"X Error:"
)} Connecting to the server failed. Please check your internet connection or contact eric@trigger.dev for help.`
);
} else {
logger.error("You must login first. Use `trigger.dev login` to login.");
logger.log(`${chalkError("X Error:")} You must login first. Use the \`login\` CLI command.`);
}
process.exitCode = 1;
return;
@@ -362,7 +366,11 @@ function useDev({
__PROJECT_CONFIG__: JSON.stringify(config),
},
plugins: [
bundleDependenciesPlugin(config),
bundleDependenciesPlugin(
"workerFacade",
(config.dependenciesToBundle ?? []).concat([/^@trigger.dev/]),
config.tsconfigPath
),
workerSetupImportConfigPlugin(configPath),
{
name: "trigger.dev v3",
@@ -631,8 +639,12 @@ async function gatherRequiredDependencies(
) {
const dependencies: Record<string, string> = {};
logger.debug("Gathering required dependencies from imports", {
imports: outputMeta.imports,
});
for (const file of outputMeta.imports) {
if (file.kind !== "require-call" || !file.external) {
if ((file.kind !== "require-call" && file.kind !== "dynamic-import") || !file.external) {
continue;
}
@@ -693,13 +705,13 @@ function createDuplicateTaskIdOutputErrorMessage(
.map((id) => {
const tasks = taskResources.filter((task) => task.id === id);
return `id "${chalkPurple(id)}" was found in:\n${tasks
.map((task) => `${task.filePath} -> ${task.exportName}`)
.join("\n")}`;
return `\n\n${chalkTask(id)} was found in:${tasks
.map((task) => `\n${task.filePath} -> ${task.exportName}`)
.join("")}`;
})
.join("\n\n");
.join("");
return `Duplicate task ids detected:\n\n${duplicateTable}\n\n`;
return `Duplicate ${chalkTask("task id")} detected:${duplicateTable}`;
}
function gatherProcessEnv() {
+10 -32
View File
@@ -1,10 +1,9 @@
import { ResolvedConfig } from "@trigger.dev/core/v3";
import type * as esbuild from "esbuild";
import type { Plugin } from "esbuild";
import { readFileSync } from "node:fs";
import { extname, isAbsolute } from "node:path";
import tsConfigPaths from "tsconfig-paths";
import { logger } from "./logger";
import { readFileSync } from "node:fs";
export function workerSetupImportConfigPlugin(configPath?: string): Plugin {
return {
@@ -37,8 +36,12 @@ export function workerSetupImportConfigPlugin(configPath?: string): Plugin {
};
}
export function bundleDependenciesPlugin(config: ResolvedConfig): Plugin {
const matchPath = config.tsconfigPath ? createMatchPath(config.tsconfigPath) : undefined;
export function bundleDependenciesPlugin(
buildIdentifier: string,
dependenciesToBundle?: Array<string | RegExp>,
tsconfigPath?: string
): Plugin {
const matchPath = tsconfigPath ? createMatchPath(tsconfigPath) : undefined;
function resolvePath(id: string) {
if (!matchPath) {
@@ -53,33 +56,8 @@ export function bundleDependenciesPlugin(config: ResolvedConfig): Plugin {
build.onResolve({ filter: /.*/ }, (args) => {
const resolvedPath = resolvePath(args.path);
logger.ignore(`Checking if ${args.path} should be bundled or external`, {
...args,
resolvedPath,
});
if (!isBareModuleId(resolvedPath)) {
logger.ignore(`Bundling ${args.path} because its not a bareModuleId`, {
...args,
});
return undefined; // let esbuild bundle it
}
if (args.path.startsWith("@trigger.dev/")) {
logger.ignore(`Bundling ${args.path} because its a trigger.dev package`, {
...args,
});
return undefined; // let esbuild bundle it
}
if (args.path === "superjson" || args.path === "copy-anything" || args.path === "is-what") {
logger.debug(`Bundling ${args.path} because its superjson/copy-anything/is-what`, {
...args,
});
return undefined; // let esbuild bundle it
return undefined; // let esbuild handle it
}
// Skip assets that are treated as files (.css, .svg, .png, etc.).
@@ -97,13 +75,13 @@ export function bundleDependenciesPlugin(config: ResolvedConfig): Plugin {
return undefined;
}
for (let pattern of config.dependenciesToBundle ?? []) {
for (let pattern of dependenciesToBundle ?? []) {
if (typeof pattern === "string" ? args.path === pattern : pattern.test(args.path)) {
return undefined; // let esbuild bundle it
}
}
logger.ignore(`Externalizing ${args.path}`, {
logger.ignore(`[${buildIdentifier}] Externalizing ${args.path}`, {
...args,
});
@@ -57,7 +57,7 @@ export async function printStandloneInitialBanner(performUpdateCheck = true) {
export function printDevBanner() {
logger.log(
`${chalkGrey("Key:")} ${chalkWorker("Worker")} ${chalkGrey("|")} ${chalkTask(
`${chalkGrey("Key:")} ${chalkWorker("Version")} ${chalkGrey("|")} ${chalkTask(
"Task"
)} ${chalkGrey("|")} ${chalkRun("Run")}`
);
@@ -18,16 +18,11 @@ import {
formatDurationMilliseconds,
workerToChildMessages,
} from "@trigger.dev/core/v3";
import chalk from "chalk";
import dotenv from "dotenv";
import { Evt } from "evt";
import { ChildProcess, fork } from "node:child_process";
import { dirname, resolve } from "node:path";
import terminalLink from "terminal-link";
import { safeDeleteFileSync } from "../../utilities/fileSystem.js";
import { installPackages } from "../../utilities/installPackages.js";
import { logger } from "../../utilities/logger.js";
import { UncaughtExceptionError } from "../common/errors.js";
import {
chalkError,
chalkGrey,
@@ -39,6 +34,10 @@ import {
chalkWorker,
prettyPrintDate,
} from "../../utilities/cliOutput.js";
import { safeDeleteFileSync } from "../../utilities/fileSystem.js";
import { installPackages } from "../../utilities/installPackages.js";
import { logger } from "../../utilities/logger.js";
import { UncaughtExceptionError } from "../common/errors.js";
export type CurrentWorkers = BackgroundWorkerCoordinator["currentWorkers"];
export class BackgroundWorkerCoordinator {
@@ -2,9 +2,10 @@ import {
Config,
ProjectConfig,
TaskExecutor,
preciseDateOriginNow,
type TracingSDK,
type HandleErrorFunction,
DurableClock,
clock,
} from "@trigger.dev/core/v3";
__WORKER_SETUP__;
@@ -42,10 +43,11 @@ import { TaskMetadataWithFunctions } from "../../types.js";
declare const sender: ZodMessageSender<typeof childToWorkerMessages>;
const preciseDateOrigin = preciseDateOriginNow();
const durableClock = new DurableClock();
clock.setGlobalClock(durableClock);
const tracer = new TriggerTracer({ tracer: otelTracer, logger: otelLogger });
const consoleInterceptor = new ConsoleInterceptor(otelLogger, preciseDateOrigin);
const consoleInterceptor = new ConsoleInterceptor(otelLogger);
const devRuntimeManager = new DevRuntimeManager();
@@ -55,7 +57,6 @@ const otelTaskLogger = new OtelTaskLogger({
logger: otelLogger,
tracer: tracer,
level: "info",
preciseDateOrigin,
});
logger.setGlobalTaskLogger(otelTaskLogger);
@@ -83,6 +84,7 @@ function getTasks(): Array<TaskMetadataWithFunctions> {
filePath: (taskFile as any).filePath,
queue: (task as any).__trigger.queue,
retry: (task as any).__trigger.retry,
machine: (task as any).__trigger.machine,
fns: (task as any).__trigger.fns,
});
}
@@ -1,6 +1,8 @@
import {
Config,
CoordinatorToProdWorkerMessages,
PostStartCauses,
PreStopCauses,
ProdWorkerToCoordinatorMessages,
TaskResource,
WaitReason,
@@ -567,23 +569,15 @@ class ProdWorker {
}
case "/preStop": {
const schema = z.enum(["index", "create", "restore"]);
const cause = schema.safeParse(url.searchParams.get("cause"));
const cause = PreStopCauses.safeParse(url.searchParams.get("cause"));
if (!cause.success) {
logger.error("Failed to parse cause", { cause });
return;
return reply.text("Failed to parse cause", 400);
}
switch (cause.data) {
case "index": {
break;
}
case "create": {
break;
}
case "restore": {
case "terminate": {
break;
}
default: {
@@ -597,13 +591,11 @@ class ProdWorker {
}
case "/postStart": {
const schema = z.enum(["index", "create", "restore"]);
const cause = schema.safeParse(url.searchParams.get("cause"));
const cause = PostStartCauses.safeParse(url.searchParams.get("cause"));
if (!cause.success) {
logger.error("Failed to parse cause", { cause });
return;
return reply.text("Failed to parse cause", 400);
}
switch (cause.data) {
@@ -678,11 +670,7 @@ class ProdWorker {
}
for (const task of this.#backgroundWorker.tasks) {
taskResources.push({
id: task.id,
filePath: task.filePath,
exportName: task.exportName,
});
taskResources.push(task);
packageVersion = task.packageVersion;
}
@@ -6,8 +6,9 @@ import {
TaskExecutor,
ZodIpcConnection,
type TracingSDK,
preciseDateOriginNow,
HandleErrorFunction,
DurableClock,
clock,
} from "@trigger.dev/core/v3";
import "source-map-support/register.js";
@@ -40,16 +41,16 @@ import * as packageJson from "../../../package.json";
import { TaskMetadataWithFunctions } from "../../types";
const preciseDateOrigin = preciseDateOriginNow();
const durableClock = new DurableClock();
clock.setGlobalClock(durableClock);
const tracer = new TriggerTracer({ tracer: otelTracer, logger: otelLogger });
const consoleInterceptor = new ConsoleInterceptor(otelLogger, preciseDateOrigin);
const consoleInterceptor = new ConsoleInterceptor(otelLogger);
const otelTaskLogger = new OtelTaskLogger({
logger: otelLogger,
tracer: tracer,
level: "info",
preciseDateOrigin,
});
logger.setGlobalTaskLogger(otelTaskLogger);
@@ -77,6 +78,7 @@ function getTasks(): Array<TaskMetadataWithFunctions> {
filePath: (taskFile as any).filePath,
queue: (task as any).__trigger.queue,
retry: (task as any).__trigger.retry,
machine: (task as any).__trigger.machine,
fns: (task as any).__trigger.fns,
});
}
@@ -200,7 +202,9 @@ const zodIpc = new ZodIpcConnection({
},
});
const prodRuntimeManager = new ProdRuntimeManager(zodIpc);
const prodRuntimeManager = new ProdRuntimeManager(zodIpc, {
waitThresholdInMs: parseInt(process.env.TRIGGER_RUNTIME_WAIT_THRESHOLD_IN_MS ?? "30000", 10),
});
runtime.setGlobalRuntimeManager(prodRuntimeManager);
+18
View File
@@ -1,5 +1,23 @@
# create-trigger
## 3.0.0-beta.2
### Patch Changes
- Updated dependencies [e3cf456c6]
- @trigger.dev/core@3.0.0-beta.2
- @trigger.dev/yalt@3.0.0-beta.2
## 3.0.0-beta.1
### Patch Changes
- Updated dependencies [b66d5525e]
- Updated dependencies [719c0a0b9]
- Updated dependencies [f93eae300]
- @trigger.dev/core@3.0.0-beta.1
- @trigger.dev/yalt@3.0.0-beta.1
## 3.0.0-beta.0
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/cli",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"description": "The Trigger.dev CLI",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
+8
View File
@@ -1,3 +1,11 @@
# @trigger.dev/core-apps
## 3.0.0-beta.2
## 3.0.0-beta.1
### Patch Changes
- b66d5525e: add machine config and secure zod connection
## 3.0.0-beta.0
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@trigger.dev/core-apps",
"description": "Backend core code used across apps",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"private": true,
"license": "MIT",
"main": "./dist/index.js",
+70 -59
View File
@@ -2,6 +2,7 @@ import { createServer } from "node:http";
import {
ClientToSharedQueueMessages,
clientWebsocketMessages,
EnvironmentType,
Machine,
PlatformToProviderMessages,
ProviderToPlatformMessages,
@@ -18,30 +19,46 @@ const MACHINE_NAME = process.env.MACHINE_NAME || "local";
const PLATFORM_HOST = process.env.PLATFORM_HOST || "127.0.0.1";
const PLATFORM_WS_PORT = process.env.PLATFORM_WS_PORT || 3030;
const PLATFORM_SECRET = process.env.PLATFORM_SECRET || "provider-secret";
const SECURE_CONNECTION = ["1", "true"].includes(process.env.SECURE_CONNECTION ?? "false");
const logger = new SimpleLogger(`[${MACHINE_NAME}]`);
export interface TaskOperationsIndexOptions {
shortCode: string;
imageRef: string;
envId: string;
apiKey: string;
apiUrl: string;
// identifiers
envId: string;
envType: EnvironmentType;
orgId: string;
projectId: string;
}
export interface TaskOperationsCreateOptions {
runId: string;
image: string;
machine: Machine;
envId: string;
version: string;
// identifiers
envId: string;
envType: EnvironmentType;
orgId: string;
projectId: string;
runId: string;
attemptId: string;
}
export interface TaskOperationsRestoreOptions {
runId: string;
imageRef: string;
checkpointRef: string;
machine: Machine;
// identifiers
envId: string;
envType: EnvironmentType;
orgId: string;
projectId: string;
runId: string;
checkpointId: string;
}
export interface TaskOperations {
@@ -87,6 +104,7 @@ export class ProviderShell implements Provider {
namespace: "shared-queue",
host: PLATFORM_HOST,
port: Number(PLATFORM_WS_PORT),
secure: SECURE_CONNECTION,
clientMessages: ClientToSharedQueueMessages,
serverMessages: SharedQueueToClientMessages,
authToken: PLATFORM_SECRET,
@@ -101,11 +119,16 @@ export class ProviderShell implements Provider {
if (message.data.type === "SCHEDULE_ATTEMPT") {
try {
this.tasks.create({
envId: message.data.envId,
runId: message.data.runId,
image: message.data.image,
machine: {},
version: message.version,
machine: message.data.machine,
version: message.data.version,
// identifiers
envId: message.data.envId,
envType: message.data.envType,
orgId: message.data.orgId,
projectId: message.data.projectId,
runId: message.data.runId,
attemptId: message.data.id,
});
} catch (error) {
logger.error("create failed", error);
@@ -138,6 +161,7 @@ export class ProviderShell implements Provider {
namespace: "provider",
host: PLATFORM_HOST,
port: Number(PLATFORM_WS_PORT),
secure: SECURE_CONNECTION,
clientMessages: ProviderToPlatformMessages,
serverMessages: PlatformToProviderMessages,
authToken: PLATFORM_SECRET,
@@ -165,9 +189,13 @@ export class ProviderShell implements Provider {
await this.tasks.index({
shortCode: message.shortCode,
imageRef: message.imageTag,
envId: message.envId,
apiKey: message.apiKey,
apiUrl: message.apiUrl,
// identifiers
envId: message.envId,
envType: message.envType,
orgId: message.orgId,
projectId: message.projectId,
});
} catch (error) {
logger.error("index failed", error);
@@ -206,13 +234,16 @@ export class ProviderShell implements Provider {
try {
await this.tasks.restore({
runId: message.runId,
checkpointRef: message.location,
machine: {
cpu: "1",
memory: "100Mi",
},
machine: message.machine,
imageRef: message.imageRef,
// identifiers
envId: message.envId,
envType: message.envType,
orgId: message.orgId,
projectId: message.projectId,
runId: message.runId,
checkpointId: message.checkpointId,
});
} catch (error) {
logger.error("restore failed", error);
@@ -230,54 +261,34 @@ export class ProviderShell implements Provider {
const reply = new HttpReply(res);
switch (req.url) {
case "/health": {
return reply.text("ok");
}
case "/whoami": {
return reply.text(`${MACHINE_NAME}`);
}
case "/close": {
this.#platformSocket.close();
return reply.text("platform socket closed");
}
case "/delete": {
const body = await getTextBody(req);
try {
const url = new URL(req.url ?? "", `http://${req.headers.host}`);
await this.tasks.delete({ runId: body });
switch (url.pathname) {
case "/health": {
return reply.text("ok");
}
case "/whoami": {
return reply.text(`${MACHINE_NAME}`);
}
case "/close": {
this.#platformSocket.close();
return reply.text("platform socket closed");
}
case "/delete": {
const body = await getTextBody(req);
return reply.text(`sent delete request: ${body}`);
}
case "/invoke": {
const body = await getTextBody(req);
await this.tasks.create({
envId: "placeholder",
image: body,
machine: {
cpu: "1",
memory: "100Mi",
},
runId: "<missing>",
version: "<missing>",
});
return reply.text(`sent restore request: ${body}`);
}
case "/restore": {
const body = await getTextBody(req);
const items = body.split("&");
const image = items[0];
const baseImageTag = items[1] ?? image;
// await this.tasks.restore({});
return reply.text(`sent restore request: ${body}`);
}
default: {
return reply.empty(404);
await this.tasks.delete({ runId: body });
return reply.text(`sent delete request: ${body}`);
}
default: {
return reply.empty(404);
}
}
} catch (error) {
logger.error("HTTP server error", { error });
reply.empty(500);
}
});
+4
View File
@@ -1,5 +1,9 @@
# @trigger.dev/core-backend
## 3.0.0-beta.2
## 3.0.0-beta.1
## 3.0.0-beta.0
## 2.3.18
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/core-backend",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"description": "Core code used across `@trigger.dev/sdk` and Trigger.dev server",
"license": "MIT",
"main": "./dist/index.js",
+14 -12
View File
@@ -94,20 +94,22 @@ export class Logger {
...args: Array<Record<string, unknown> | undefined>
) {
// Get the current context from trace if it exists
const currentContext = trace.getSpan(context.active());
const currentSpan = trace.getSpan(context.active());
const structuredLog = {
...structureArgs(safeJsonClone(args) as Record<string, unknown>[], this.#filteredKeys),
...this.#additionalFields(),
timestamp: new Date(),
name: this.#name,
message,
level,
traceId: currentContext?.spanContext().traceId,
parentSpanId: currentContext?.spanContext().spanId,
};
if (!currentSpan || currentSpan.isRecording()) {
const structuredLog = {
...structureArgs(safeJsonClone(args) as Record<string, unknown>[], this.#filteredKeys),
...this.#additionalFields(),
timestamp: new Date(),
name: this.#name,
message,
level,
traceId: currentSpan?.spanContext().traceId,
parentSpanId: currentSpan?.spanContext().spanId,
};
loggerFunction(JSON.stringify(structuredLog, this.#jsonReplacer));
loggerFunction(JSON.stringify(structuredLog, this.#jsonReplacer));
}
}
}
+14
View File
@@ -1,5 +1,19 @@
# internal-platform
## 3.0.0-beta.2
### Patch Changes
- e3cf456c6: Handle string and non-stringifiable outputs like functions
## 3.0.0-beta.1
### Patch Changes
- b66d5525e: add machine config and secure zod connection
- 719c0a0b9: Fixed incorrect span timings around checkpoints by implementing a precise wall clock that resets after restores
- f93eae300: Dynamically import superjson and fix some bundling issues
## 3.0.0-beta.0
### Major Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@trigger.dev/core",
"version": "3.0.0-beta.0",
"version": "3.0.0-beta.2",
"description": "Core code used across the Trigger.dev SDK and platform",
"license": "MIT",
"main": "./dist/index.js",
+5
View File
@@ -0,0 +1,5 @@
// Split module-level variable definition into separate files to allow
// tree-shaking on each api instance.
import { ClockAPI } from "./clock";
/** Entrypoint for clock API */
export const clock = ClockAPI.getInstance();
+6
View File
@@ -0,0 +1,6 @@
export type ClockTime = [number, number];
export interface Clock {
preciseNow(): ClockTime;
reset(): void;
}
+37
View File
@@ -0,0 +1,37 @@
const API_NAME = "clock";
import { getGlobal, registerGlobal } from "../utils/globals";
import type { Clock, ClockTime } from "./clock";
import { SimpleClock } from "./simpleClock";
const SIMPLE_CLOCK = new SimpleClock();
export class ClockAPI {
private static _instance?: ClockAPI;
private constructor() {}
public static getInstance(): ClockAPI {
if (!this._instance) {
this._instance = new ClockAPI();
}
return this._instance;
}
public setGlobalClock(clock: Clock): boolean {
return registerGlobal(API_NAME, clock);
}
public preciseNow(): ClockTime {
return this.#getClock().preciseNow();
}
public reset(): void {
this.#getClock().reset();
}
#getClock(): Clock {
return getGlobal(API_NAME) ?? SIMPLE_CLOCK;
}
}
@@ -0,0 +1,46 @@
import { PreciseDate } from "@google-cloud/precise-date";
import { Clock, ClockTime } from "./clock";
export type PreciseWallClockOptions = {
origin?: ClockTime;
now?: PreciseDate;
};
export class PreciseWallClock implements Clock {
private _origin: {
clockTime: ClockTime;
preciseDate: PreciseDate;
};
get #originClockTime() {
return this._origin.clockTime;
}
get #originPreciseDate() {
return this._origin.preciseDate;
}
constructor(options: PreciseWallClockOptions = {}) {
this._origin = {
clockTime: options.origin ?? process.hrtime(),
preciseDate: options.now ?? new PreciseDate(),
};
}
preciseNow(): [number, number] {
const elapsedHrTime = process.hrtime(this.#originClockTime);
const elapsedNanoseconds = BigInt(elapsedHrTime[0]) * BigInt(1e9) + BigInt(elapsedHrTime[1]);
const preciseDate = new PreciseDate(this.#originPreciseDate.getFullTime() + elapsedNanoseconds);
const dateStruct = preciseDate.toStruct();
return [dateStruct.seconds, dateStruct.nanos];
}
reset() {
this._origin = {
clockTime: process.hrtime(),
preciseDate: new PreciseDate(),
};
}
}
+15
View File
@@ -0,0 +1,15 @@
import { PreciseDate } from "@google-cloud/precise-date";
import { Clock } from "./clock";
export class SimpleClock implements Clock {
preciseNow(): [number, number] {
const now = new PreciseDate();
const nowStruct = now.toStruct();
return [nowStruct.seconds, nowStruct.nanos];
}
reset() {
// do nothing
}
}
+15 -11
View File
@@ -4,11 +4,11 @@ import util from "node:util";
import { iconStringForSeverity } from "./icons";
import { SemanticInternalAttributes } from "./semanticInternalAttributes";
import { flattenAttributes } from "./utils/flattenAttributes";
import { type PreciseDateOrigin, calculatePreciseDateHrTime } from "./utils/preciseDate";
import { ClockTime } from "./clock/clock";
import { clock } from "./clock-api";
export class ConsoleInterceptor {
constructor(private readonly logger: logsAPI.Logger, private readonly preciseDateOrigin: PreciseDateOrigin) { }
constructor(private readonly logger: logsAPI.Logger) {}
// Intercept the console and send logs to the OpenTelemetry logger
// during the execution of the callback
@@ -39,24 +39,28 @@ export class ConsoleInterceptor {
}
log(...args: unknown[]): void {
this.#handleLog(SeverityNumber.INFO, "Log", ...args);
this.#handleLog(SeverityNumber.INFO, this.#getTimestampInHrTime(), "Log", ...args);
}
info(...args: unknown[]): void {
this.#handleLog(SeverityNumber.INFO, "Info", ...args);
this.#handleLog(SeverityNumber.INFO, this.#getTimestampInHrTime(), "Info", ...args);
}
warn(...args: unknown[]): void {
this.#handleLog(SeverityNumber.WARN, "Warn", ...args);
this.#handleLog(SeverityNumber.WARN, this.#getTimestampInHrTime(), "Warn", ...args);
}
error(...args: unknown[]): void {
this.#handleLog(SeverityNumber.ERROR, "Error", ...args);
this.#handleLog(SeverityNumber.ERROR, this.#getTimestampInHrTime(), "Error", ...args);
}
#handleLog(severityNumber: SeverityNumber, severityText: string, ...args: unknown[]): void {
#handleLog(
severityNumber: SeverityNumber,
timestamp: ClockTime,
severityText: string,
...args: unknown[]
): void {
const body = util.format(...args);
const timestamp = this.#getTimestampInHrTime();
const parsed = tryParseJSON(body);
@@ -81,8 +85,8 @@ export class ConsoleInterceptor {
});
}
#getTimestampInHrTime(): [number, number] {
return calculatePreciseDateHrTime(this.preciseDateOrigin);
#getTimestampInHrTime(): ClockTime {
return clock.preciseNow();
}
#getAttributes(severityNumber: SeverityNumber): logsAPI.LogAttributes {
+3 -6
View File
@@ -9,6 +9,7 @@ export * from "./zodIpc";
export * from "./errors";
export * from "./runtime-api";
export * from "./logger-api";
export * from "./clock-api";
export * from "./types";
export * from "./limits";
export { SemanticInternalAttributes } from "./semanticInternalAttributes";
@@ -35,6 +36,7 @@ export { taskContextManager, TaskContextSpanProcessor } from "./tasks/taskContex
export type { RuntimeManager } from "./runtime/manager";
export { DevRuntimeManager } from "./runtime/devRuntimeManager";
export { ProdRuntimeManager } from "./runtime/prodRuntimeManager";
export { PreciseWallClock as DurableClock } from "./clock/preciseWallClock";
export { TriggerTracer } from "./tracer";
export type { TaskLogger } from "./logger/taskLogger";
@@ -57,17 +59,12 @@ export { omit } from "./utils/omit";
export { TracingSDK, type TracingDiagnosticLogLevel, recordSpanException } from "./otel";
export { TaskExecutor, type TaskExecutorOptions } from "./workers/taskExecutor";
export { detectDependencyVersion } from "./utils/detectDependencyVersion";
export {
type PreciseDateOrigin,
calculatePreciseDateHrTime,
preciseDateOriginNow,
} from "./utils/preciseDate";
export {
parsePacket,
stringifyIO,
prettyPrintPacket,
createPacketAttributes,
createPackageAttributesAsJson,
createPacketAttributesAsJson,
conditionallyExportPacket,
conditionallyImportPacket,
packetRequiresOffloading,
+16 -17
View File
@@ -4,7 +4,8 @@ import { iconStringForSeverity } from "../icons";
import { SemanticInternalAttributes } from "../semanticInternalAttributes";
import { TriggerTracer } from "../tracer";
import { flattenAttributes } from "../utils/flattenAttributes";
import { PreciseDateOrigin, calculatePreciseDateHrTime } from "../utils/preciseDate";
import { ClockTime } from "../clock/clock";
import { clock } from "../clock-api";
export type LogLevel = "log" | "error" | "warn" | "info" | "debug";
@@ -14,7 +15,6 @@ export type TaskLoggerConfig = {
logger: Logger;
tracer: TriggerTracer;
level: LogLevel;
preciseDateOrigin: PreciseDateOrigin;
};
export interface TaskLogger {
@@ -36,41 +36,40 @@ export class OtelTaskLogger implements TaskLogger {
debug(message: string, properties?: Record<string, unknown>) {
if (this._level < 4) return;
this.#emitLog(message, "debug", SeverityNumber.DEBUG, properties);
this.#emitLog(message, this.#getTimestampInHrTime(), "debug", SeverityNumber.DEBUG, properties);
}
log(message: string, properties?: Record<string, unknown>) {
if (this._level < 2) return;
this.#emitLog(message, "log", SeverityNumber.INFO, properties);
this.#emitLog(message, this.#getTimestampInHrTime(), "log", SeverityNumber.INFO, properties);
}
info(message: string, properties?: Record<string, unknown>) {
if (this._level < 3) return;
this.#emitLog(message, "info", SeverityNumber.INFO, properties);
this.#emitLog(message, this.#getTimestampInHrTime(), "info", SeverityNumber.INFO, properties);
}
warn(message: string, properties?: Record<string, unknown>) {
if (this._level < 1) return;
this.#emitLog(message, "warn", SeverityNumber.WARN, properties);
this.#emitLog(message, this.#getTimestampInHrTime(), "warn", SeverityNumber.WARN, properties);
}
error(message: string, properties?: Record<string, unknown>) {
if (this._level < 0) return;
this.#emitLog(message, "error", SeverityNumber.ERROR, properties);
this.#emitLog(message, this.#getTimestampInHrTime(), "error", SeverityNumber.ERROR, properties);
}
#emitLog(
message: string,
timestamp: ClockTime,
severityText: string,
severityNumber: SeverityNumber,
properties?: Record<string, unknown>
) {
const timestamp = this.#getTimestampInHrTime();
let attributes: Attributes = { ...flattenAttributes(properties) };
const icon = iconStringForSeverity(severityNumber);
@@ -83,7 +82,7 @@ export class OtelTaskLogger implements TaskLogger {
severityText,
body: message,
attributes,
timestamp
timestamp,
});
}
@@ -91,17 +90,17 @@ export class OtelTaskLogger implements TaskLogger {
return this._config.tracer.startActiveSpan(name, fn, options);
}
#getTimestampInHrTime(): [number, number] {
return calculatePreciseDateHrTime(this._config.preciseDateOrigin);
#getTimestampInHrTime(): ClockTime {
return clock.preciseNow();
}
}
export class NoopTaskLogger implements TaskLogger {
debug() { }
log() { }
info() { }
warn() { }
error() { }
debug() {}
log() {}
info() {}
warn() {}
error() {}
trace<T>(name: string, fn: (span: Span) => Promise<T>): Promise<T> {
return fn({} as Span);
}
+34 -6
View File
@@ -15,16 +15,18 @@ import {
detectResourcesSync,
processDetectorSync,
} from "@opentelemetry/resources";
import { LoggerProvider, SimpleLogRecordProcessor } from "@opentelemetry/sdk-logs";
import {
BatchLogRecordProcessor,
LoggerProvider,
SimpleLogRecordProcessor,
} from "@opentelemetry/sdk-logs";
import {
BatchSpanProcessor,
NodeTracerProvider,
SimpleSpanProcessor,
SpanExporter,
} from "@opentelemetry/sdk-trace-node";
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";
import { SemanticInternalAttributes } from "../semanticInternalAttributes";
import { TaskContextLogProcessor, TaskContextSpanProcessor } from "../tasks/taskContextManager";
import { getEnvVar } from "../utils/getEnv";
import {
OTEL_ATTRIBUTE_PER_EVENT_COUNT_LIMIT,
OTEL_ATTRIBUTE_PER_LINK_COUNT_LIMIT,
@@ -35,6 +37,9 @@ import {
OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT,
OTEL_SPAN_EVENT_COUNT_LIMIT,
} from "../limits";
import { SemanticInternalAttributes } from "../semanticInternalAttributes";
import { TaskContextLogProcessor, TaskContextSpanProcessor } from "../tasks/taskContextManager";
import { getEnvVar } from "../utils/getEnv";
class AsyncResourceDetector implements DetectorSync {
private _promise: Promise<ResourceAttributes>;
@@ -130,8 +135,22 @@ export class TracingSDK {
});
traceProvider.addSpanProcessor(
new TaskContextSpanProcessor(new SimpleSpanProcessor(spanExporter))
new TaskContextSpanProcessor(
getEnvVar("OTEL_BATCH_PROCESSING_ENABLED") === "1"
? new BatchSpanProcessor(spanExporter, {
maxExportBatchSize: parseInt(getEnvVar("OTEL_SPAN_MAX_EXPORT_BATCH_SIZE") ?? "64"),
scheduledDelayMillis: parseInt(
getEnvVar("OTEL_SPAN_SCHEDULED_DELAY_MILLIS") ?? "200"
),
exportTimeoutMillis: parseInt(
getEnvVar("OTEL_SPAN_EXPORT_TIMEOUT_MILLIS") ?? "30000"
),
maxQueueSize: parseInt(getEnvVar("OTEL_SPAN_MAX_QUEUE_SIZE") ?? "512"),
})
: new SimpleSpanProcessor(spanExporter)
)
);
traceProvider.register();
registerInstrumentations({
@@ -153,7 +172,16 @@ export class TracingSDK {
});
loggerProvider.addLogRecordProcessor(
new TaskContextLogProcessor(new SimpleLogRecordProcessor(logExporter))
new TaskContextLogProcessor(
getEnvVar("OTEL_BATCH_PROCESSING_ENABLED") === "1"
? new BatchLogRecordProcessor(logExporter, {
maxExportBatchSize: parseInt(getEnvVar("OTEL_LOG_MAX_EXPORT_BATCH_SIZE") ?? "64"),
scheduledDelayMillis: parseInt(getEnvVar("OTEL_LOG_SCHEDULED_DELAY_MILLIS") ?? "200"),
exportTimeoutMillis: parseInt(getEnvVar("OTEL_LOG_EXPORT_TIMEOUT_MILLIS") ?? "30000"),
maxQueueSize: parseInt(getEnvVar("OTEL_LOG_MAX_QUEUE_SIZE") ?? "512"),
})
: new SimpleLogRecordProcessor(logExporter)
)
);
this._logProvider = loggerProvider;
@@ -5,7 +5,6 @@ import {
TaskRunExecution,
TaskRunExecutionResult,
} from "../schemas";
import { conditionallyImportPacket } from "../utils/ioSerialization";
import { RuntimeManager } from "./manager";
export class DevRuntimeManager implements RuntimeManager {
@@ -1,3 +1,4 @@
import { clock } from "../clock-api";
import {
BatchTaskRunExecutionResult,
ProdChildToWorkerMessages,
@@ -9,6 +10,11 @@ import {
} from "../schemas";
import { ZodIpcConnection } from "../zodIpc";
import { RuntimeManager } from "./manager";
import { setTimeout } from "node:timers/promises";
export type ProdRuntimeManagerOptions = {
waitThresholdInMs?: number;
};
export class ProdRuntimeManager implements RuntimeManager {
_taskWaits: Map<
@@ -21,7 +27,7 @@ export class ProdRuntimeManager implements RuntimeManager {
{ resolve: (value: BatchTaskRunExecutionResult) => void; reject: (err?: any) => void }
> = new Map();
_waitForRestore: { resolve: (value?: any) => void; reject: (err?: any) => void } | undefined;
_waitForRestore: { resolve: (value: "restore") => void; reject: (err?: any) => void } | undefined;
_tasks: Map<string, TaskMetadataWithFilePath> = new Map();
@@ -29,7 +35,8 @@ export class ProdRuntimeManager implements RuntimeManager {
private ipc: ZodIpcConnection<
typeof ProdWorkerToChildMessages,
typeof ProdChildToWorkerMessages
>
>,
private options: ProdRuntimeManagerOptions = {}
) {}
disable(): void {
@@ -47,20 +54,16 @@ export class ProdRuntimeManager implements RuntimeManager {
}
async waitForDuration(ms: number): Promise<void> {
let timeout: NodeJS.Timeout | undefined;
const now = Date.now();
const resolveAfterDuration = new Promise((resolve) => {
timeout = setTimeout(resolve, ms);
});
const resolveAfterDuration = setTimeout(ms, "duration" as const);
if (ms < 10_000) {
if (ms <= this.waitThresholdInMs) {
await resolveAfterDuration;
return;
}
const waitForRestore = new Promise((resolve, reject) => {
const waitForRestore = new Promise<"restore">((resolve, reject) => {
this._waitForRestore = { resolve, reject };
});
@@ -81,8 +84,6 @@ export class ProdRuntimeManager implements RuntimeManager {
// The coordinator can then cancel any in-progress checkpoints
this.ipc.send("CANCEL_CHECKPOINT", {});
clearTimeout(timeout);
}
resumeAfterRestore(): void {
@@ -90,7 +91,10 @@ export class ProdRuntimeManager implements RuntimeManager {
return;
}
this._waitForRestore.resolve();
// Resets the clock to the current time
clock.reset();
this._waitForRestore.resolve("restore");
this._waitForRestore = undefined;
}
@@ -155,4 +159,8 @@ export class ProdRuntimeManager implements RuntimeManager {
this._taskWaits.delete(execution.run.id);
}
private get waitThresholdInMs(): number {
return this.options.waitThresholdInMs ?? 30_000;
}
}

Some files were not shown because too many files have changed in this diff Show More