Skip to main content
Glama
redis.ts2.83 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { sleep } from '@medplum/core'; import Redis from 'ioredis'; import type { MedplumRedisConfig } from './config/types'; import { getLogger } from './logger'; let redis: Redis | undefined = undefined; let redisSubscribers: Set<Redis> | undefined = undefined; export function initRedis(config: MedplumRedisConfig): void { redis = new Redis({ ...config, reconnectOnError: (err) => { if (err.message.includes('READONLY')) { // Reconnect and retry if the connected instance got marked as read-only; // this happens during Redis service updates when the cluster fails over // between primary and replica instances return 2; } getLogger().warn('Unhandled Redis error', err); return false; // Do not reconnect on other errors }, }); } export async function closeRedis(): Promise<void> { if (redis) { const tmpRedis = redis; const tmpSubscribers = redisSubscribers; redis = undefined; redisSubscribers = undefined; if (tmpSubscribers) { for (const subscriber of tmpSubscribers) { subscriber.disconnect(); } } await tmpRedis.quit(); await sleep(100); } } /** * Gets the global `Redis` instance. * * The `duplicate` method is intentionally omitted to prevent accidental calling of `Redis.quit` * which can cause the global instance to fail to shutdown gracefully later on. * * Instead {@link getRedisSubscriber} should be called to obtain a `Redis` instance for use as a subscriber-mode client. * * @returns The global `Redis` instance. */ export function getRedis(): Redis & { duplicate: never } { if (!redis) { throw new Error('Redis not initialized'); } // @ts-expect-error We don't want anyone to call `duplicate on the redis global instance // This is because we want to gracefully `quit` and duplicated Redis instances will return redis; } /** * Gets a `Redis` instance for use in subscriber mode. * * The synchronous `.disconnect()` on this instance should be called instead of `.quit()` when you want to disconnect. * * @returns A `Redis` instance to use as a subscriber client. */ export function getRedisSubscriber(): Redis & { quit: never } { if (!redis) { throw new Error('Redis not initialized'); } if (!redisSubscribers) { redisSubscribers = new Set(); } const subscriber = redis.duplicate(); redisSubscribers.add(subscriber); subscriber.on('end', () => { redisSubscribers?.delete(subscriber); }); return subscriber as Redis & { quit: never }; } /** * @returns The amount of active `Redis` subscriber instances. */ export function getRedisSubscriberCount(): number { return redisSubscribers?.size ?? 0; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server