mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-13 21:01:21 +08:00
Fix unhandled promise rejections in rawQuery
This commit is contained in:
parent
b493a89130
commit
4b9c7fe0ef
@ -26,7 +26,7 @@ export function ensurePolyfilled() {
|
||||
process.on("unhandledRejection", (reason, promise) => {
|
||||
captureError("unhandled-promise-rejection", reason);
|
||||
if (getNodeEnvironment() === "development") {
|
||||
console.error("\x1b[41mUnhandled promise rejection. Some production environments will kill the server in this case, so the server will now exit. Please use the `ignoreUnhandledRejection` function to signal that you've handled the error.\x1b[0m", reason);
|
||||
console.error("\x1b[41mUnhandled promise rejection. Some production environments (particularly Vercel) will kill the server in this case, so the server will now exit. Please use the `ignoreUnhandledRejection` function to signal that you've handled the error.\x1b[0m", reason);
|
||||
}
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@ -2,7 +2,9 @@ import { Prisma, PrismaClient } from "@prisma/client";
|
||||
import { withAccelerate } from "@prisma/extension-accelerate";
|
||||
import { getEnvVariable, getNodeEnvironment } from '@stackframe/stack-shared/dist/utils/env';
|
||||
import { deepPlainEquals, filterUndefined, typedFromEntries, typedKeys } from "@stackframe/stack-shared/dist/utils/objects";
|
||||
import { ignoreUnhandledRejection } from "@stackframe/stack-shared/dist/utils/promises";
|
||||
import { Result } from "@stackframe/stack-shared/dist/utils/results";
|
||||
import { isPromise } from "util/types";
|
||||
import { traceSpan } from "./utils/telemetry";
|
||||
|
||||
// In dev mode, fast refresh causes us to recreate many Prisma clients, eventually overloading the database.
|
||||
@ -130,8 +132,15 @@ async function rawQueryArray<Q extends RawQuery<any>[]>(queries: Q): Promise<[]
|
||||
const index = +type.slice(1);
|
||||
unprocessed[index].push(row.json);
|
||||
}
|
||||
const postProcessed = queries.map((q, index) => q.postProcess(unprocessed[index]));
|
||||
return postProcessed as any;
|
||||
const postProcessed = queries.map((q, index) => {
|
||||
const postProcessed = q.postProcess(unprocessed[index]);
|
||||
// If the postProcess is async, postProcessed is a Promise. If that Promise is rejected, it will cause an unhandled promise rejection.
|
||||
// We don't want that, because Vercel crashes on unhandled promise rejections.
|
||||
if (isPromise(postProcessed)) {
|
||||
ignoreUnhandledRejection(postProcessed);
|
||||
}
|
||||
});
|
||||
return postProcessed;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ export function ensurePolyfilled() {
|
||||
process.on("unhandledRejection", (reason, promise) => {
|
||||
captureError("unhandled-promise-rejection", reason);
|
||||
if (getNodeEnvironment() === "development") {
|
||||
console.error("Unhandled promise rejection. Some production environments will kill the server in this case, so the server will now exit. Please use the `ignoreUnhandledRejection` function to signal that you've handled the error.", reason);
|
||||
console.error("Unhandled promise rejection. Some production environments (particularly Vercel) will kill the server in this case, so the server will now exit. Please use the `ignoreUnhandledRejection` function to signal that you've handled the error.", reason);
|
||||
}
|
||||
if ((globalThis.process as any).exit) {
|
||||
globalThis.process.exit(1);
|
||||
|
||||
@ -132,7 +132,9 @@ export function rejected<T>(reason: unknown): ReactPromise<T> {
|
||||
return rejectedCache.get([reason]) as ReactPromise<T>;
|
||||
}
|
||||
|
||||
const res = Object.assign(ignoreUnhandledRejection(Promise.reject(reason)), {
|
||||
const promise = Promise.reject(reason);
|
||||
ignoreUnhandledRejection(promise);
|
||||
const res = Object.assign(promise, {
|
||||
status: "rejected",
|
||||
reason: reason,
|
||||
} as const);
|
||||
@ -223,26 +225,22 @@ import.meta.vitest?.test("pending", async ({ expect }) => {
|
||||
*
|
||||
* Vercel kills serverless functions on unhandled promise rejection errors, so this is important.
|
||||
*/
|
||||
export function ignoreUnhandledRejection<T extends Promise<any>>(promise: T): T {
|
||||
export function ignoreUnhandledRejection<T extends Promise<any>>(promise: T): void {
|
||||
promise.catch(() => {});
|
||||
return promise;
|
||||
}
|
||||
import.meta.vitest?.test("ignoreUnhandledRejection", async ({ expect }) => {
|
||||
// Test with a promise that resolves
|
||||
const resolvePromise = Promise.resolve(42);
|
||||
const ignoredResolvePromise = ignoreUnhandledRejection(resolvePromise);
|
||||
expect(ignoredResolvePromise).toBe(resolvePromise); // Should return the same promise
|
||||
expect(await ignoredResolvePromise).toBe(42); // Should still resolve to the same value
|
||||
ignoreUnhandledRejection(resolvePromise);
|
||||
expect(await resolvePromise).toBe(42); // Should still resolve to the same value
|
||||
|
||||
// Test with a promise that rejects
|
||||
const error = new Error("Test error");
|
||||
const rejectPromise = Promise.reject(error);
|
||||
const ignoredRejectPromise = ignoreUnhandledRejection(rejectPromise);
|
||||
expect(ignoredRejectPromise).toBe(rejectPromise); // Should return the same promise
|
||||
|
||||
// The promise should still reject, but the rejection is caught internally
|
||||
// so it doesn't cause an unhandled rejection error
|
||||
await expect(ignoredRejectPromise).rejects.toBe(error);
|
||||
const error = new Error("Test error");
|
||||
const rejectPromise = Promise.reject(error);
|
||||
ignoreUnhandledRejection(rejectPromise);
|
||||
await expect(rejectPromise).rejects.toBe(error);
|
||||
});
|
||||
|
||||
export async function wait(ms: number) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user