52c9d485f8
* fix trailing slash in api url * add maybe platform down error * shorten config path * extend protobuf compiler install instructions * build command and image model * new image triggers task indexing * index support for prod builds * shorten example provider secret * multi-stage task prod build * lock prod tasks to node 18 image * extract shared build and dev command libs * pull out more shared deps * add coordinator and providers * fix core-apps build * add dev builds for new apps * fix cwd * enable corepack * some build fixes * enable buildkit for old docker versions * coordinator image fixes * update provider containerfile * build dev images in parallel * upgrade pgadmin * fix prod facade build * prod runs * fix merge * don't knock out platform on invalid attempt id * fix prod facade * rename to build.ts * fix prod builds * set to executing after fetching payload * make prod worker listen on random port if in use * remove experimental warnings in dev * prod resume * prevent execution after completion * exit prod worker after completion * always restart otel collector * docker checkpoints and prod runtime messaging * don't retry indexing without chance of success * make platform checkpoint aware * deploy with existing hash sets latest worker * log restore requests * only try to checkpoint long waits * tidying up * lockfile * fix build * prod worker merge fixes * fix prod complete and cancel * fix lua nil checks * socket namespace abstraction * cleanup * make all build args optional * add build script * don't require env vars for dev * fix schema * prod merge * small fix * bind correct logger * fix v3 ref catalog entry * resume prod batch * pass socket to error and disconnect handlers * fix non-batch resume * fix batch resume * send connection env vars when not in dev * create worker via socket * move api client back into v3 cli * fix lockfile * fix resume with failures * marqs replace message * typecheck prior to build * don't define api url in prod builds * support prod retries after resume * skip typecheck option
125 lines
3.6 KiB
TypeScript
125 lines
3.6 KiB
TypeScript
import path from "path";
|
|
import express from "express";
|
|
import compression from "compression";
|
|
import morgan from "morgan";
|
|
import { createRequestHandler } from "@remix-run/express";
|
|
import { WebSocketServer } from "ws";
|
|
import { broadcastDevReady, logDevReady } from "@remix-run/server-runtime";
|
|
import type { Server as IoServer } from "socket.io";
|
|
import type { Server as EngineServer } from "engine.io";
|
|
|
|
const app = express();
|
|
|
|
app.use((req, res, next) => {
|
|
// helpful headers:
|
|
res.set("Strict-Transport-Security", `max-age=${60 * 60 * 24 * 365 * 100}`);
|
|
|
|
// /clean-urls/ -> /clean-urls
|
|
if (req.path.endsWith("/") && req.path.length > 1) {
|
|
const query = req.url.slice(req.path.length);
|
|
const safepath = req.path.slice(0, -1).replace(/\/+/g, "/");
|
|
res.redirect(301, safepath + query);
|
|
return;
|
|
}
|
|
next();
|
|
});
|
|
|
|
if (process.env.DISABLE_COMPRESSION !== "1") {
|
|
app.use(compression());
|
|
}
|
|
|
|
// http://expressjs.com/en/advanced/best-practice-security.html#at-a-minimum-disable-x-powered-by-header
|
|
app.disable("x-powered-by");
|
|
|
|
// Remix fingerprints its assets so we can cache forever.
|
|
app.use("/build", express.static("public/build", { immutable: true, maxAge: "1y" }));
|
|
|
|
// Everything else (like favicon.ico) is cached for an hour. You may want to be
|
|
// more aggressive with this caching.
|
|
app.use(express.static("public", { maxAge: "1h" }));
|
|
|
|
app.use(morgan("tiny"));
|
|
|
|
const MODE = process.env.NODE_ENV;
|
|
const BUILD_DIR = path.join(process.cwd(), "build");
|
|
const build = require(BUILD_DIR);
|
|
|
|
app.all(
|
|
"*",
|
|
createRequestHandler({
|
|
build,
|
|
mode: MODE,
|
|
})
|
|
);
|
|
|
|
const port = process.env.REMIX_APP_PORT || process.env.PORT || 3000;
|
|
|
|
if (process.env.HTTP_SERVER_DISABLED !== "true") {
|
|
const socketIo: { io: IoServer } | undefined = build.entry.module.socketIo;
|
|
const wss: WebSocketServer | undefined = build.entry.module.wss;
|
|
|
|
const server = app.listen(port, () => {
|
|
console.log(`✅ app ready: http://localhost:${port} [NODE_ENV: ${MODE}]`);
|
|
|
|
if (MODE === "development") {
|
|
broadcastDevReady(build)
|
|
.then(() => logDevReady(build))
|
|
.catch(console.error);
|
|
}
|
|
});
|
|
|
|
server.keepAliveTimeout = 65 * 1000;
|
|
|
|
process.on("SIGTERM", () => {
|
|
server.close((err) => {
|
|
if (err) {
|
|
console.error("Error closing express server:", err);
|
|
} else {
|
|
console.log("Express server closed gracefully.");
|
|
}
|
|
});
|
|
});
|
|
|
|
socketIo?.io.attach(server);
|
|
server.removeAllListeners("upgrade"); // prevent duplicate upgrades from listeners created by io.attach()
|
|
|
|
server.on("upgrade", async (req, socket, head) => {
|
|
console.log(
|
|
`Attemping to upgrade connection at url ${req.url} with headers: ${JSON.stringify(
|
|
req.headers
|
|
)}`
|
|
);
|
|
|
|
const url = new URL(req.url ?? "", "http://localhost");
|
|
|
|
// Upgrade socket.io connection
|
|
if (url.pathname.startsWith("/socket.io/")) {
|
|
console.log(`Socket.io client connected, upgrading their connection...`);
|
|
|
|
// https://github.com/socketio/socket.io/issues/4693
|
|
(socketIo?.io.engine as EngineServer).handleUpgrade(req, socket, head);
|
|
return;
|
|
}
|
|
|
|
// Only upgrade the connecting if the path is `/ws`
|
|
if (url.pathname !== "/ws") {
|
|
socket.destroy(
|
|
new Error(
|
|
"Cannot connect because of invalid path: Please include `/ws` in the path of your upgrade request."
|
|
)
|
|
);
|
|
return;
|
|
}
|
|
|
|
console.log(`Client connected, upgrading their connection...`);
|
|
|
|
// Handle the WebSocket connection
|
|
wss?.handleUpgrade(req, socket, head, (ws) => {
|
|
wss?.emit("connection", ws, req);
|
|
});
|
|
});
|
|
} else {
|
|
require(BUILD_DIR);
|
|
console.log(`✅ app ready (skipping http server)`);
|
|
}
|