Files
speckle-server/packages/server/modules/shared/redis/redis.ts
T
Iain Sproat 2071a36e5d fix(previews): disable previews is previews Redis is not reachable
- exit preview-service process if Redis is not reachable
- improve server healthcheck to include Redis client readiness check
2025-04-11 13:25:19 +01:00

71 lines
2.4 KiB
TypeScript

import { redisLogger } from '@/observability/logging'
import Redis, { RedisOptions } from 'ioredis'
import {
EnvironmentResourceError,
MisconfiguredEnvironmentError
} from '@/modules/shared/errors'
import { getRedisUrl } from '@/modules/shared/helpers/envHelper'
import { ensureError } from '@speckle/shared'
export function createRedisClient(redisUrl: string, redisOptions: RedisOptions): Redis {
let redisClient: Redis
try {
redisClient = new Redis(redisUrl, redisOptions)
redisClient.on('error', (err) => {
redisLogger.error(err, 'Redis encountered an error.')
if (err instanceof Error) {
throw new EnvironmentResourceError('Redis encountered an error.', err) //FIXME backoff and retry?
}
throw new EnvironmentResourceError('Redis encountered an error.') //FIXME backoff and retry?
})
} catch (err) {
redisLogger.error(err, 'Could not create Redis client')
if (err instanceof Error) {
throw new MisconfiguredEnvironmentError('Unable to connect to Redis.', err) //FIXME backoff and retry?
}
throw new MisconfiguredEnvironmentError('Unable to connect to Redis.') //FIXME backoff and retry?
}
return redisClient
}
let redisClient: Redis | undefined = undefined
export const getGenericRedis = (): Redis => {
if (!redisClient) redisClient = createRedisClient(getRedisUrl(), {})
return redisClient
}
export const isRedisReady = (client: Redis) => {
// MIT Licensed: https://github.com/OptimalBits/bull/blob/develop/LICENSE.md
// Reference: https://github.com/OptimalBits/bull/blob/develop/lib/utils.js
return new Promise<void>((resolve, reject) => {
if (client.status === 'ready') {
resolve()
} else {
function handleReady() {
client.removeListener('end', handleEnd)
client.removeListener('error', handleError)
resolve()
}
function handleError(e: unknown) {
const err = ensureError(e, 'Unknown error in Redis client')
client.removeListener('ready', handleReady)
client.removeListener('error', handleError)
reject(err)
}
function handleEnd() {
client.removeListener('ready', handleReady)
client.removeListener('error', handleError)
reject(new Error('Redis connection ended'))
}
client.once('ready', handleReady)
client.on('error', handleError)
client.once('end', handleEnd)
}
})
}