fix: memory leak fixes for nextjs.

Addresses high memory usage by adding gzip compression to nginx (removing it from nextjs)
socket cleanup handling, and tRPC client optimizations.

Ref: https://github.com/homarr-labs/homarr/issues/3759
This commit is contained in:
KimP0ssible-no committed 2026-04-15 12:15:29 +02:00
1 parent 6a45645354
commit c5e69c3e40
7 files changed
+41 -4

No files matched your search

+1
View File
@@ -19,6 +19,7 @@ const withNextIntl = createNextIntlPlugin({
const nextConfig: NextConfig = {
output: "standalone",
compress: false, // Workaround for vercel/next.js#89091 - zlib retains ServerResponse after client disconnect, causing CLOSE-WAIT socket leak
reactStrictMode: true,
// react compiler breaks mantine-react-table, so disabled for now
//reactCompiler: true,
+27
View File
@@ -0,0 +1,27 @@
// Periodic cleanup of zombie CLOSE-WAIT sockets in Next.js standalone mode.
// Workaround for vercel/next.js#89091 — AfterContext retains ServerResponse
// after client disconnect, leaving sockets in CLOSE-WAIT indefinitely.
//
// Usage: node --require ./socket-cleanup.cjs server.js
// or: NODE_OPTIONS="--require /app/socket-cleanup.cjs" node server.js
const INTERVAL_MS = 60_000; // Check every 60 seconds
setInterval(() => {
let destroyed = 0;
for (const handle of process._getActiveHandles()) {
if (
handle.constructor?.name === "Socket" &&
handle.localPort === 3000 &&
handle.readyState === "writeOnly" &&
!handle._httpMessage &&
handle.bytesWritten === 0
) {
handle.destroy();
destroyed++;
}
}
if (destroyed > 0) {
console.log(`[socket-cleanup] Destroyed ${destroyed} zombie socket(s)`);
}
}, INTERVAL_MS).unref(); // unref() so this timer doesn't prevent process exit
@@ -7,7 +7,7 @@ import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import { ReactQueryStreamedHydration } from "@tanstack/react-query-next-experimental";
import {
createWSClient,
httpBatchStreamLink,
httpBatchLink,
httpLink,
isNonJsonSerializable,
loggerLink,
@@ -90,7 +90,7 @@ export function TRPCReactProvider(props: PropsWithChildren) {
url: getTrpcUrl(),
headers: createHeadersCallbackForSource("nextjs-react (form-data)"),
}),
false: httpBatchStreamLink({
false: httpBatchLink({
transformer: superjson,
url: getTrpcUrl(),
maxURLLength: 2083, // Suggested by tRPC: https://trpc.io/docs/client/links/httpBatchLink#setting-a-maximum-url-length