possible fix for 502
This commit is contained in:
@@ -505,6 +505,45 @@ process.on('uncaughtException', err => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Session cache ────────────────────────────────────────────────────────
|
||||||
|
// The session middleware runs in parallel with all other app.use() handlers
|
||||||
|
// (flummpress uses Promise.all). With many concurrent requests each doing a
|
||||||
|
// DB SELECT, the pool (max:50) drains and nginx sees 502s. Caching the
|
||||||
|
// session row for 5s and the upload-count for 30s eliminates the hot path.
|
||||||
|
const SESSION_CACHE_TTL = 5_000; // ms — short enough to pick up bans quickly
|
||||||
|
const UPLOAD_COUNT_CACHE_TTL = 30_000; // ms — upload window is 12h, stale for 30s is fine
|
||||||
|
const _sessionCache = new Map(); // sha256(cookie) -> { data: row, exp: number }
|
||||||
|
const _uploadCountCache = new Map(); // username -> { count: number, exp: number }
|
||||||
|
|
||||||
|
const _scGet = (hash) => {
|
||||||
|
const e = _sessionCache.get(hash);
|
||||||
|
if (e && e.exp > Date.now()) return e.data;
|
||||||
|
_sessionCache.delete(hash);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
const _scSet = (hash, data) => {
|
||||||
|
_sessionCache.set(hash, { data, exp: Date.now() + SESSION_CACHE_TTL });
|
||||||
|
if (_sessionCache.size > 2000) {
|
||||||
|
const now = Date.now();
|
||||||
|
for (const [k, v] of _sessionCache) if (v.exp <= now) _sessionCache.delete(k);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Exposed so logout/ban routes can force-evict immediately
|
||||||
|
global._invalidateSessionCache = (hash) => _sessionCache.delete(hash);
|
||||||
|
|
||||||
|
const _ucGet = (username) => {
|
||||||
|
const e = _uploadCountCache.get(username);
|
||||||
|
if (e && e.exp > Date.now()) return e.count;
|
||||||
|
_uploadCountCache.delete(username);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
const _ucSet = (username, count) => {
|
||||||
|
_uploadCountCache.set(username, { count, exp: Date.now() + UPLOAD_COUNT_CACHE_TTL });
|
||||||
|
};
|
||||||
|
// Allow upload handler to bust the cache after a successful upload
|
||||||
|
global._invalidateUploadCountCache = (username) => _uploadCountCache.delete(username);
|
||||||
|
// ──────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
app.use(async (req, res) => {
|
app.use(async (req, res) => {
|
||||||
// This can be used to annoy people on discord sending links to your site lmao, shouldnt be used though since it sucks ass
|
// This can be used to annoy people on discord sending links to your site lmao, shouldnt be used though since it sucks ass
|
||||||
// if (cfg.main.development && req.method === 'POST') console.error(`[BOOT] [DEBUG_POST] ${req.method} ${req.url.pathname}`);
|
// if (cfg.main.development && req.method === 'POST') console.error(`[BOOT] [DEBUG_POST] ${req.method} ${req.url.pathname}`);
|
||||||
@@ -571,14 +610,22 @@ process.on('uncaughtException', err => {
|
|||||||
req.fullscreen = req.cookies.fullscreen || 0;
|
req.fullscreen = req.cookies.fullscreen || 0;
|
||||||
|
|
||||||
if (req.cookies.session) {
|
if (req.cookies.session) {
|
||||||
const user = await db`
|
const _sessionHash = lib.sha256(req.cookies.session);
|
||||||
|
let _cachedRow = _scGet(_sessionHash);
|
||||||
|
let user;
|
||||||
|
if (_cachedRow) {
|
||||||
|
user = [_cachedRow];
|
||||||
|
} else {
|
||||||
|
user = await db`
|
||||||
select "user".id, "user".login, "user".user, "user".admin, "user".is_moderator, "user".banned, "user".ban_reason, "user".ban_expires, "user".force_password_change, "user_sessions".id as sess_id, "user_sessions".csrf_token, "user_options".mode, "user_options".theme, "user_options".fullscreen, "user_options".excluded_tags, "user_options".avatar, "user_options".avatar_file, "user_options".show_motd, "user_options".strict_mode, "user_options".show_background, "user_options".use_new_layout, "user_options".username_color, "user_options".font, "user_options".disable_autoplay, "user_options".disable_swiping, "user_options".description, "user_options".display_name, COALESCE("user_options".min_xd_score, 0) as min_xd_score, "user_options".ruffle_volume, "user_options".ruffle_background, "user_options".quote_emojis, "user_options".embed_youtube_in_comments, "user_options".hide_koepfe, "user_options".language, "user_options".use_alternative_infobox, "user_options".use_alternative_steuerung, "user_options".receive_system_notifications, "user_options".receive_user_notifications, "user_options".do_not_disturb, "user_options".comment_display_mode, "user_options".force_comment_display_mode
|
select "user".id, "user".login, "user".user, "user".admin, "user".is_moderator, "user".banned, "user".ban_reason, "user".ban_expires, "user".force_password_change, "user_sessions".id as sess_id, "user_sessions".csrf_token, "user_options".mode, "user_options".theme, "user_options".fullscreen, "user_options".excluded_tags, "user_options".avatar, "user_options".avatar_file, "user_options".show_motd, "user_options".strict_mode, "user_options".show_background, "user_options".use_new_layout, "user_options".username_color, "user_options".font, "user_options".disable_autoplay, "user_options".disable_swiping, "user_options".description, "user_options".display_name, COALESCE("user_options".min_xd_score, 0) as min_xd_score, "user_options".ruffle_volume, "user_options".ruffle_background, "user_options".quote_emojis, "user_options".embed_youtube_in_comments, "user_options".hide_koepfe, "user_options".language, "user_options".use_alternative_infobox, "user_options".use_alternative_steuerung, "user_options".receive_system_notifications, "user_options".receive_user_notifications, "user_options".do_not_disturb, "user_options".comment_display_mode, "user_options".force_comment_display_mode
|
||||||
from "user_sessions"
|
from "user_sessions"
|
||||||
left join "user" on "user".id = "user_sessions".user_id
|
left join "user" on "user".id = "user_sessions".user_id
|
||||||
left join "user_options" on "user_options".user_id = "user_sessions".user_id
|
left join "user_options" on "user_options".user_id = "user_sessions".user_id
|
||||||
where "user_sessions".session = ${lib.sha256(req.cookies.session)}
|
where "user_sessions".session = ${_sessionHash}
|
||||||
limit 1
|
limit 1
|
||||||
`;
|
`;
|
||||||
|
if (user.length > 0) _scSet(_sessionHash, user[0]);
|
||||||
|
}
|
||||||
|
|
||||||
if (user.length === 0) {
|
if (user.length === 0) {
|
||||||
res.writeHead(307, { // delete session
|
res.writeHead(307, { // delete session
|
||||||
@@ -651,8 +698,10 @@ process.on('uncaughtException', err => {
|
|||||||
req.session.pending_count = pending[0].c;
|
req.session.pending_count = pending[0].c;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate uploads remaining globally for the modal
|
// Calculate uploads remaining globally for the modal (cached 30s per user)
|
||||||
if (!req.session.admin && !req.session.is_moderator) {
|
if (!req.session.admin && !req.session.is_moderator) {
|
||||||
|
let cachedUploadCount = _ucGet(req.session.user);
|
||||||
|
if (cachedUploadCount === null) {
|
||||||
const twelveHoursAgo = ~~(Date.now() / 1000) - (12 * 3600);
|
const twelveHoursAgo = ~~(Date.now() / 1000) - (12 * 3600);
|
||||||
const uploadCount = await db`
|
const uploadCount = await db`
|
||||||
SELECT count(*) as count
|
SELECT count(*) as count
|
||||||
@@ -661,7 +710,10 @@ process.on('uncaughtException', err => {
|
|||||||
AND stamp > ${twelveHoursAgo}
|
AND stamp > ${twelveHoursAgo}
|
||||||
AND is_deleted = false
|
AND is_deleted = false
|
||||||
`;
|
`;
|
||||||
req.session.uploads_remaining = Math.max(0, cfg.main.upload_limit - parseInt(uploadCount[0].count));
|
cachedUploadCount = parseInt(uploadCount[0].count);
|
||||||
|
_ucSet(req.session.user, cachedUploadCount);
|
||||||
|
}
|
||||||
|
req.session.uploads_remaining = Math.max(0, cfg.main.upload_limit - cachedUploadCount);
|
||||||
} else {
|
} else {
|
||||||
req.session.uploads_remaining = undefined; // Unlimited for admins/mods
|
req.session.uploads_remaining = undefined; // Unlimited for admins/mods
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user