shellphone.app/server/index.ts

119 lines
3.0 KiB
TypeScript
Raw Normal View History

2022-06-26 15:01:55 +00:00
import express from "express";
2022-05-14 10:22:06 +00:00
import compression from "compression";
import morgan from "morgan";
import { createRequestHandler } from "@remix-run/express";
2022-06-26 15:01:55 +00:00
import * as Sentry from "@sentry/node";
2022-05-14 10:22:06 +00:00
2022-06-26 15:01:55 +00:00
import config from "~/config/config.server";
2022-05-14 10:22:06 +00:00
import logger from "~/utils/logger.server";
2022-06-26 15:01:55 +00:00
import { adminMiddleware, setupBullBoard } from "./queues";
import { registerSentry, sentryLoadContext } from "./sentry-remix";
import { purgeRequireCache } from "./purge-require-cache";
const environment = process.env.NODE_ENV;
2022-06-26 15:01:55 +00:00
if (config.sentry.dsn) {
Sentry.init({
dsn: config.sentry.dsn,
integrations: [new Sentry.Integrations.Http({ tracing: true })],
tracesSampleRate: 1.0,
environment,
});
}
2022-05-14 10:22:06 +00:00
const app = express();
app.use((req, res, next) => {
res.set("X-Fly-Region", process.env.FLY_REGION ?? "unknown");
res.set("Strict-Transport-Security", `max-age=31536000; preload`);
next();
});
// replay non-GET/HEAD/OPTIONS requests to the primary Fly.io region rather than read-only Postgres instances
// learn more: https://fly.io/docs/getting-started/multi-region-databases/#replay-the-request
app.all("*", (req, res, next) => {
const { method, path: pathname } = req;
const { PRIMARY_REGION, FLY_REGION } = process.env;
const isMethodReplayable = !["GET", "OPTIONS", "HEAD"].includes(method);
const isReadOnlyRegion = FLY_REGION && PRIMARY_REGION && FLY_REGION !== PRIMARY_REGION;
const shouldReplay = isMethodReplayable && isReadOnlyRegion;
if (!shouldReplay) {
return next();
}
const logInfo = {
pathname,
method,
PRIMARY_REGION,
FLY_REGION,
};
logger.info("Replaying:", logInfo);
res.set("fly-replay", `region=${PRIMARY_REGION}`);
return res.sendStatus(409);
});
app.disable("x-powered-by");
app.use(
compression({
filter(req, res) {
const contentTypeHeader = res.getHeader("Content-Type");
let contentType = "";
if (contentTypeHeader) {
if (Array.isArray(contentTypeHeader)) {
contentType = contentTypeHeader.join(" ");
} else {
contentType = String(contentTypeHeader);
}
}
if (contentType.includes("text/event-stream")) {
return false;
}
return true;
},
}),
);
2022-05-14 10:22:06 +00:00
// cache static and immutable assets
app.use(express.static("public", { immutable: true, maxAge: "1y" }));
// setup background queues and cron jobs
app.use("/admin", adminMiddleware);
app.use("/admin/queues", setupBullBoard().getRouter());
app.use(morgan("tiny"));
app.all("*", (req, res, next) => {
if (environment !== "production") {
2022-05-14 10:22:06 +00:00
purgeRequireCache();
}
return createRequestHandler({
2022-06-26 15:01:55 +00:00
build: registerSentry(require("../build")),
mode: environment,
2022-06-26 15:01:55 +00:00
getLoadContext: sentryLoadContext,
2022-05-14 10:22:06 +00:00
})(req, res, next);
});
const port = process.env.PORT || 3000;
app.listen(port, () => {
logger.info(`Server listening on port ${port}`);
});
if (environment !== "production") {
process.on("SIGUSR2", () => process.exit(229));
process.on("exit", (exitCode) => {
if (exitCode !== 229) {
return;
2022-05-14 10:22:06 +00:00
}
require("child_process").spawn(process.argv.shift(), process.argv, {
cwd: process.cwd(),
detached: true,
stdio: "inherit",
});
});
2022-05-14 10:22:06 +00:00
}