Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f089c4b232 | ||
|
|
b6f6701eda | ||
|
|
c5e69c3e40 |
No files matched your search
+3
-1
@@ -71,4 +71,6 @@ en.d.json.ts
|
||||
|
||||
# personal agent config
|
||||
AGENTS.md
|
||||
.opencode
|
||||
.opencode
|
||||
.claude/CLAUDE.md
|
||||
.claude/settings.json
|
||||
@@ -52,6 +52,7 @@ COPY --from=builder /app/packages/db/migrations ./db/migrations
|
||||
# Automatically leverage output traces to reduce image size
|
||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||
COPY --from=builder /app/apps/nextjs/.next/standalone ./
|
||||
COPY --from=builder /app/apps/nextjs/socket-cleanup.cjs ./apps/nextjs/socket-cleanup.cjs
|
||||
COPY --from=builder /app/apps/nextjs/.next/static ./apps/nextjs/.next/static
|
||||
COPY --from=builder /app/apps/nextjs/public ./apps/nextjs/public
|
||||
COPY scripts/run.sh ./run.sh
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// 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
|
||||
|
||||
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
|
||||
|
||||
@@ -3,6 +3,12 @@ events {
|
||||
}
|
||||
|
||||
http {
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript image/svg+xml;
|
||||
gzip_min_length 1000;
|
||||
gzip_proxied any;
|
||||
gzip_vary on;
|
||||
|
||||
server {
|
||||
listen 7575;
|
||||
listen [::]:7575;
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ TASKS_PID=$!
|
||||
node apps/websocket/wssServer.cjs &
|
||||
WSS_PID=$!
|
||||
|
||||
node apps/nextjs/server.js &
|
||||
node --max-old-space-size=1024 --require ./apps/nextjs/socket-cleanup.cjs apps/nextjs/server.js &
|
||||
NEXTJS_PID=$!
|
||||
|
||||
# Function to handle SIGTERM and shut down services
|
||||
|
||||
Reference in new issue
Block a user