diff --git a/backend/.env.example b/backend/.env.example index 8873515c..9554626b 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -66,3 +66,10 @@ DWENGO_AUTH_TEACHER_JWKS_ENDPOINT=http://hostname/realms/teacher/protocol/openid # The address of the Loki instance, a log aggregation system. # If running your stack in docker, this should use the docker service name. #DWENGO_LOGGING_LOKI_HOST=http://localhost:3102 + +# The hostname or IP address of the Redis cache. +# If running your stack in docker, this should use the docker service name. +#DWENGO_CACHE_HOST=localhost +#DWENGO_CACHE_PORT=6379 +#DWENGO_CACHE_TTL=3600 +#DWENGO_CACHE_KEY_PREFIX=dwengo diff --git a/backend/.env.production.example b/backend/.env.production.example index 4f36cf53..e41b7a91 100644 --- a/backend/.env.production.example +++ b/backend/.env.production.example @@ -35,3 +35,7 @@ DWENGO_AUTH_TEACHER_JWKS_ENDPOINT=http://idp:7080/idp/realms/teacher/protocol/op DWENGO_LOGGING_LEVEL=info DWENGO_LOGGING_LOKI_HOST=http://logging:3102 + +DWENGO_CACHE_HOST=cache +#DWENGO_CACHE_PORT=6379 +DWENGO_CACHE_TTL=604800 diff --git a/backend/.env.staging b/backend/.env.staging index bedfb0b7..52e98b48 100644 --- a/backend/.env.staging +++ b/backend/.env.staging @@ -1,4 +1,6 @@ PORT=3000 +DWENGO_RUN_MODE=staging + DWENGO_DB_HOST=db DWENGO_DB_PORT=5432 DWENGO_DB_USERNAME=postgres @@ -18,4 +20,8 @@ DWENGO_CORS_ALLOWED_ORIGINS=http://localhost/*,http://idp:7080,https://idp:7080 # Logging and monitoring -LOKI_HOST=http://logging:3102 +DWENGO_LOGGING_LEVEL=debug +DWENGO_LOGGING_LOKI_HOST=http://logging:3102 + +DWENGO_CACHE_HOST=caching +DWENGO_CACHE_TTL=86400 diff --git a/backend/src/caching.ts b/backend/src/caching.ts new file mode 100644 index 00000000..09fd85e8 --- /dev/null +++ b/backend/src/caching.ts @@ -0,0 +1,42 @@ +import { createClient, RedisClientType } from 'redis'; +import { getLogger } from './logging/initalize.js'; +import { envVars, getEnvVar } from './util/envVars.js'; + +export type CacheClient = RedisClientType; + +let redisClient: CacheClient; + +async function initializeClient(): Promise { + if (redisClient !== undefined) { + return redisClient; + } + + const redisHost = getEnvVar(envVars.CacheHost); + const redisPort = getEnvVar(envVars.CachePort); + const redisUrl = `redis://${redisHost}:${redisPort}`; + + redisClient = createClient({ + url: redisUrl + }); + + redisClient.on('error', (err) => getLogger().error('Redis error:', err)); + await redisClient.connect(); + + return redisClient; +} + +export async function getCacheClient(): Promise { + redisClient ||= await initializeClient(); + return redisClient; +} + +export async function checkRedisHealth(): Promise { + try { + await redisClient.set('health', 'ok'); + const reply = await redisClient.get('health'); + return reply === 'ok'; + } catch (error) { + getLogger().error('Redis Health Check Failed:', error); + return false; + } +} diff --git a/backend/src/util/envVars.ts b/backend/src/util/envVars.ts index d5bf9fcf..e9b2f452 100644 --- a/backend/src/util/envVars.ts +++ b/backend/src/util/envVars.ts @@ -5,6 +5,7 @@ const STUDENT_IDP_PREFIX = IDP_PREFIX + 'STUDENT_'; const TEACHER_IDP_PREFIX = IDP_PREFIX + 'TEACHER_'; const CORS_PREFIX = PREFIX + 'CORS_'; const LOGGING_PREFIX = PREFIX + 'LOGGING_'; +const CACHE_PREFIX = PREFIX + 'CACHE_'; interface EnvVar { key: string; @@ -39,6 +40,11 @@ export const envVars: Record = { LogLevel: { key: LOGGING_PREFIX + 'LEVEL', defaultValue: 'info' }, LokiHost: { key: LOGGING_PREFIX + 'LOKI_HOST', defaultValue: 'http://localhost:3102' }, + + CacheHost: { key: CACHE_PREFIX + 'HOST', defaultValue: 'localhost' }, + CachePort: { key: CACHE_PREFIX + 'PORT', defaultValue: 6379 }, + CacheTTL: { key: CACHE_PREFIX + 'TTL', defaultValue: 60 * 60 * 24 }, // 24 hours + CacheKeyPrefix: { key: CACHE_PREFIX + 'KEY_PREFIX', defaultValue: 'dwengo' }, } as const; /**