Skip to content

Commit 43bc7ed

Browse files
committed
Hoist uncaughtException handler to the top of workers to better report error messages
1 parent 4fdb7f8 commit 43bc7ed

File tree

6 files changed

+52
-51
lines changed

6 files changed

+52
-51
lines changed

.changeset/big-tomatoes-deliver.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"trigger.dev": patch
3+
---
4+
5+
Hoist uncaughtException handler to the top of workers to better report error messages

packages/cli-v3/src/commands/deploy.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,13 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
202202
projectRef: options.projectRef,
203203
});
204204

205+
if (resolvedConfig.status === "error") {
206+
logger.error("Failed to read config:", resolvedConfig.error);
207+
span && recordSpanException(span, resolvedConfig.error);
208+
209+
throw new SkipLoggingError("Failed to read config");
210+
}
211+
205212
logger.debug("Resolved config", { resolvedConfig });
206213

207214
span?.setAttributes({
@@ -1126,6 +1133,9 @@ async function compileProject(
11261133
format: "cjs", // This is needed to support opentelemetry instrumentation that uses module patching
11271134
target: ["node18", "es2020"],
11281135
outdir: "out",
1136+
banner: {
1137+
js: `process.on("uncaughtException", function(error, origin) { if (error instanceof Error) { process.send && process.send({ type: "EVENT", message: { type: "UNCAUGHT_EXCEPTION", payload: { error: { name: error.name, message: error.message, stack: error.stack }, origin }, version: "v1" } }); } else { process.send && process.send({ type: "EVENT", message: { type: "UNCAUGHT_EXCEPTION", payload: { error: { name: "Error", message: typeof error === "string" ? error : JSON.stringify(error) }, origin }, version: "v1" } }); } });`,
1138+
},
11291139
define: {
11301140
TRIGGER_API_URL: `"${config.triggerUrl}"`,
11311141
__PROJECT_CONFIG__: JSON.stringify(config),

packages/cli-v3/src/commands/dev.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,11 @@ async function startDev(
153153

154154
logger.debug("Initial config", { config });
155155

156+
if (config.status === "error") {
157+
logger.error("Failed to read config", config.error);
158+
process.exit(1);
159+
}
160+
156161
async function getDevReactElement(
157162
configParam: ResolvedConfig,
158163
authorization: { apiUrl: string; accessToken: string },
@@ -164,18 +169,18 @@ async function startDev(
164169
apiClient = new CliApiClient(apiUrl, accessToken);
165170

166171
const devEnv = await apiClient.getProjectEnv({
167-
projectRef: config.config.project,
172+
projectRef: configParam.project,
168173
env: "dev",
169174
});
170175

171176
if (!devEnv.success) {
172177
if (devEnv.error === "Project not found") {
173178
logger.error(
174-
`Project not found: ${config.config.project}. Ensure you are using the correct project ref and CLI profile (use --profile). Currently using the "${options.profile}" profile, which points to ${authorization.apiUrl}`
179+
`Project not found: ${configParam.project}. Ensure you are using the correct project ref and CLI profile (use --profile). Currently using the "${options.profile}" profile, which points to ${authorization.apiUrl}`
175180
);
176181
} else {
177182
logger.error(
178-
`Failed to initialize dev environment: ${devEnv.error}. Using project ref ${config.config.project}`
183+
`Failed to initialize dev environment: ${devEnv.error}. Using project ref ${configParam.project}`
179184
);
180185
}
181186

@@ -388,6 +393,9 @@ function useDev({
388393
resolveDir: process.cwd(),
389394
sourcefile: "__entryPoint.ts",
390395
},
396+
banner: {
397+
js: `process.on("uncaughtException", function(error, origin) { if (error instanceof Error) { process.send && process.send({ type: "UNCAUGHT_EXCEPTION", payload: { error: { name: error.name, message: error.message, stack: error.stack }, origin }, version: "v1" }); } else { process.send && process.send({ type: "UNCAUGHT_EXCEPTION", payload: { error: { name: "Error", message: typeof error === "string" ? error : JSON.stringify(error) }, origin }, version: "v1" }); } });`,
398+
},
391399
bundle: true,
392400
metafile: true,
393401
write: false,
@@ -602,10 +610,10 @@ function useDev({
602610
} else {
603611
}
604612

605-
if (e.originalError.stack) {
613+
if (e.originalError.message || e.originalError.stack) {
606614
logger.log(
607615
`${chalkError("X Error:")} Worker failed to start`,
608-
e.originalError.stack
616+
e.originalError.stack ?? e.originalError.message
609617
);
610618
}
611619

packages/cli-v3/src/utilities/configFiles.ts

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ export type ReadConfigResult =
126126
| {
127127
status: "in-memory";
128128
config: ResolvedConfig;
129+
}
130+
| {
131+
status: "error";
132+
error: unknown;
129133
};
130134

131135
export async function readConfig(
@@ -182,22 +186,29 @@ export async function readConfig(
182186
],
183187
});
184188

185-
// import the config file
186-
const userConfigModule = await import(builtConfigFileHref);
189+
try {
190+
// import the config file
191+
const userConfigModule = await import(builtConfigFileHref);
187192

188-
// The --project-ref CLI arg will always override the project specified in the config file
189-
const rawConfig = await normalizeConfig(
190-
userConfigModule?.config,
191-
options?.projectRef ? { project: options?.projectRef } : undefined
192-
);
193+
// The --project-ref CLI arg will always override the project specified in the config file
194+
const rawConfig = await normalizeConfig(
195+
userConfigModule?.config,
196+
options?.projectRef ? { project: options?.projectRef } : undefined
197+
);
193198

194-
const config = Config.parse(rawConfig);
199+
const config = Config.parse(rawConfig);
195200

196-
return {
197-
status: "file",
198-
config: await resolveConfig(absoluteDir, config),
199-
path: configPath,
200-
};
201+
return {
202+
status: "file",
203+
config: await resolveConfig(absoluteDir, config),
204+
path: configPath,
205+
};
206+
} catch (error) {
207+
return {
208+
status: "error",
209+
error,
210+
};
211+
}
201212
}
202213

203214
export async function resolveConfig(path: string, config: Config): Promise<ResolvedConfig> {

packages/cli-v3/src/workers/dev/worker-setup.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,4 @@ export const sender = new ZodMessageSender({
3333
},
3434
});
3535

36-
process.on("uncaughtException", (error, origin) => {
37-
sender
38-
.send("UNCAUGHT_EXCEPTION", {
39-
error: {
40-
name: error.name,
41-
message: error.message,
42-
stack: error.stack,
43-
},
44-
origin,
45-
})
46-
.catch((err) => {
47-
console.error("Failed to send UNCAUGHT_EXCEPTION message", err);
48-
});
49-
});
50-
5136
taskCatalog.setGlobalTaskCatalog(new StandardTaskCatalog());

packages/cli-v3/src/workers/prod/worker-setup.ts

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,4 @@ export const tracingSDK = new TracingSDK({
1919
diagLogLevel: (process.env.OTEL_LOG_LEVEL as TracingDiagnosticLogLevel) ?? "none",
2020
});
2121

22-
process.on("uncaughtException", (error, origin) => {
23-
process.send?.({
24-
type: "EVENT",
25-
message: {
26-
type: "UNCAUGHT_EXCEPTION",
27-
payload: {
28-
error: {
29-
name: error.name,
30-
message: error.message,
31-
stack: error.stack,
32-
},
33-
origin,
34-
},
35-
version: "v1",
36-
},
37-
});
38-
});
39-
4022
taskCatalog.setGlobalTaskCatalog(new StandardTaskCatalog());

0 commit comments

Comments
 (0)