diff --git a/config.sample.yml b/config.sample.yml index 47edd8d28f..579a64495e 100644 --- a/config.sample.yml +++ b/config.sample.yml @@ -31,6 +31,28 @@ db: db: wiki ssl: false + # Optional - How often (in ms) to clean up expired sessions from the DB (default: 86400000 = 1 day) + # sessionCleanupInterval: 86400000 + + # Optional - How often (in ms) the /healthz endpoint checks the DB (default: 14400000 = 4 hours) + # healthCheckInterval: 14400000 + +# --------------------------------------------------------------------- +# Analytics +# --------------------------------------------------------------------- + +# analytics: + # Optional - How long (in seconds) to cache analytics config (default: 86400 = 1 day) + # cacheTTL: 86400 + +# --------------------------------------------------------------------- +# Authentication +# --------------------------------------------------------------------- + +# auth: + # Optional - How long (in seconds) to cache deserialized users (default: 14400 = 4 hours, 0 to disable) + # userCacheTTL: 14400 + # Optional - PostgreSQL / MySQL / MariaDB only: # -> Uncomment lines you need below and set `auto` to false # -> Full list of accepted options: https://nodejs.org/api/tls.html#tls_tls_createsecurecontext_options diff --git a/dev/build/config.yml b/dev/build/config.yml index d9e58761a1..392a236839 100644 --- a/dev/build/config.yml +++ b/dev/build/config.yml @@ -9,6 +9,10 @@ db: db: $(DB_NAME) storage: $(DB_FILEPATH) ssl: $(DB_SSL) + sessionCleanupInterval: $(DB_SESSION_CLEANUP_INTERVAL:60000) + healthCheckInterval: $(DB_HEALTH_CHECK_INTERVAL:14400000) +pool: + min: $(DB_POOL_MIN:2) ssl: enabled: $(SSL_ACTIVE) port: 3443 @@ -18,3 +22,7 @@ ssl: logLevel: $(LOG_LEVEL:info) logFormat: $(LOG_FORMAT:default) ha: $(HA_ACTIVE) +analytics: + cacheTTL: $(ANALYTICS_CACHE_TTL:86400) +auth: + userCacheTTL: $(AUTH_USER_CACHE_TTL:14400) diff --git a/server/app/data.yml b/server/app/data.yml index 0cd628a6c9..495518ed0a 100644 --- a/server/app/data.yml +++ b/server/app/data.yml @@ -18,10 +18,12 @@ defaults: storage: ./db.sqlite sslOptions: auto: true + sessionCleanupInterval: 60000 + healthCheckInterval: 14400000 ssl: enabled: false pool: - min: 1 + min: 2 bindIP: 0.0.0.0 logLevel: info logFormat: default @@ -61,6 +63,8 @@ defaults: iconset: 'md' darkMode: false tocPosition: 'left' + analytics: + cacheTTL: 86400 auth: autoLogin: false enforce2FA: false @@ -69,6 +73,7 @@ defaults: audience: 'urn:wiki.js' tokenExpiration: '30m' tokenRenewal: '14d' + userCacheTTL: 14400 editShortcuts: editFab: true editMenuBar: false diff --git a/server/controllers/common.js b/server/controllers/common.js index dec6fa3aa7..12811ee54c 100644 --- a/server/controllers/common.js +++ b/server/controllers/common.js @@ -22,16 +22,6 @@ router.get('/robots.txt', (req, res, next) => { } }) -/** - * Health Endpoint - */ -router.get('/healthz', (req, res, next) => { - if (WIKI.models.knex.client.pool.numFree() < 1 && WIKI.models.knex.client.pool.numUsed() < 1) { - res.status(503).json({ ok: false }).end() - } else { - res.status(200).json({ ok: true }).end() - } -}) /** * Administration diff --git a/server/core/auth.js b/server/core/auth.js index fb30c970c2..1da18ae5d6 100644 --- a/server/core/auth.js +++ b/server/core/auth.js @@ -21,6 +21,7 @@ module.exports = { groups: {}, validApiKeys: [], revocationList: require('./cache').init(), + userCache: require('./cache').init(), /** * Initialize the authentication module @@ -34,10 +35,20 @@ module.exports = { passport.deserializeUser(async (id, done) => { try { + const ttl = WIKI.config.auth.userCacheTTL + if (ttl > 0) { + const cached = this.userCache.get(id) + if (cached !== undefined) { + return done(null, cached) + } + } const user = await WIKI.models.users.query().findById(id).withGraphFetched('groups').modifyGraph('groups', builder => { builder.select('groups.id', 'permissions') }) if (user) { + if (ttl > 0) { + this.userCache.set(id, user, ttl) + } done(null, user) } else { done(new Error(WIKI.lang.t('auth:errors:usernotfound')), null) diff --git a/server/master.js b/server/master.js index 0679777ef8..23a6fdcb6f 100644 --- a/server/master.js +++ b/server/master.js @@ -71,6 +71,26 @@ module.exports = async () => { app.use('/', ctrl.ssl) + // ---------------------------------------- + // Health Endpoint (before Passport to avoid DB queries on healthcheck) + // ---------------------------------------- + + let healthLastCheck = 0 + let healthLastOk = false + app.get('/healthz', async (req, res) => { + const now = Date.now() + if (now - healthLastCheck > WIKI.config.db.healthCheckInterval) { + try { + await WIKI.models.knex.raw('SELECT 1') + healthLastOk = true + } catch (err) { + healthLastOk = false + } + healthLastCheck = now + } + res.status(healthLastOk ? 200 : 503).json({ ok: healthLastOk }).end() + }) + // ---------------------------------------- // Passport Authentication // ---------------------------------------- @@ -81,7 +101,8 @@ module.exports = async () => { resave: false, saveUninitialized: false, store: new KnexSessionStore({ - knex: WIKI.models.knex + knex: WIKI.models.knex, + clearInterval: WIKI.config.db.sessionCleanupInterval }) })) app.use(WIKI.auth.passport.initialize()) diff --git a/server/models/analytics.js b/server/models/analytics.js index 17a3f6ab54..6895d7a407 100644 --- a/server/models/analytics.js +++ b/server/models/analytics.js @@ -127,7 +127,7 @@ module.exports = class Analytics extends Model { analyticsCode.bodyEnd += code.bodyEnd } - await WIKI.cache.set('analytics', analyticsCode, 300) + await WIKI.cache.set('analytics', analyticsCode, WIKI.config.analytics.cacheTTL) return analyticsCode } catch (err) {