Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(redis): sentinel support #8260

Merged
merged 4 commits into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/ten-houses-unite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@graphql-mesh/types': patch
'@graphql-mesh/cache-redis': patch
---

Support Redis Sentinels - [See more](https://github.com/redis/ioredis?tab=readme-ov-file#sentinel)
21 changes: 20 additions & 1 deletion packages/cache/redis/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,23 @@ export default class RedisCache<V = string> implements KeyValueCache<V>, Disposa

constructor(options: YamlConfig.Cache['redis'] & { pubsub?: MeshPubSub; logger: Logger }) {
const lazyConnect = options.lazyConnect !== false;
if (options.url) {
if ('sentinels' in options) {
this.client = new Redis({
name: options.name,
sentinelPassword:
options.sentinelPassword && interpolateStrWithEnv(options.sentinelPassword),
sentinels: options.sentinels.map(s => ({
host: s.host && interpolateStrWithEnv(s.host),
port: s.port && parseInt(interpolateStrWithEnv(s.port)),
family: s.family && parseInt(interpolateStrWithEnv(s.family)),
})),
role: options.role,
enableTLSForSentinelMode: options.enableTLSForSentinelMode,
enableAutoPipelining: true,
enableOfflineQueue: true,
lazyConnect,
});
} else if (options.url) {
const redisUrl = new URL(interpolateStrWithEnv(options.url));

if (!['redis:', 'rediss:'].includes(redisUrl.protocol)) {
Expand Down Expand Up @@ -50,6 +66,8 @@ export default class RedisCache<V = string> implements KeyValueCache<V>, Disposa
const parsedPassword =
interpolateStrWithEnv(options.password?.toString()) || process.env.REDIS_PASSWORD;
const parsedDb = interpolateStrWithEnv(options.db?.toString()) || process.env.REDIS_DB;
const parsedFamily =
interpolateStrWithEnv(options.family?.toString()) || process.env.REDIS_FAMILY;
const numPort = parseInt(parsedPort);
const numDb = parseInt(parsedDb);
if (parsedHost) {
Expand All @@ -60,6 +78,7 @@ export default class RedisCache<V = string> implements KeyValueCache<V>, Disposa
username: parsedUsername,
password: parsedPassword,
db: isNaN(numDb) ? undefined : numDb,
family: parsedFamily === '6' ? 6 : undefined,
...(lazyConnect ? { lazyConnect: true } : {}),
enableAutoPipelining: true,
enableOfflineQueue: true,
Expand Down
45 changes: 44 additions & 1 deletion packages/cache/redis/yaml-config.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,56 @@ type Cache {
redis: RedisConfig
}

type RedisConfig @md {
union RedisConfig = RedisConfigSentinel | RedisConfigSingle

type RedisConfigSentinel @md {
"""
identifies a group of Redis instances composed of a master and one or more slaves
"""
name: String!
"""
(optional) password for Sentinel instances.
"""
sentinelPassword: String
"""
A list of sentinels to connect to. The list does not need to enumerate all your sentinel instances, but a few so that if one is down the client will try the next one.
"""
sentinels: [RedisSentinelConfig!]!
"""
(optional) with a value of slave will return a random slave from the Sentinel group.
"""
role: RedisSentinelRole
"""
(optional) set to true if connecting to sentinel instances that are encrypted
"""
enableTLSForSentinelMode: Boolean
"""
Flag to indicate lazyConnect value for Redis client.

@default: true
"""
lazyConnect: Boolean
}

enum RedisSentinelRole {
master
slave
}

type RedisSentinelConfig @md {
host: String
port: String
family: String
}

type RedisConfigSingle @md {
host: String
port: String
username: String
password: String
db: Int
url: String
family: String
"""
Flag to indicate lazyConnect value for Redis client.

Expand Down
70 changes: 67 additions & 3 deletions packages/legacy/types/src/config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,15 @@
"$ref": "#/definitions/LocalforageConfig"
},
"redis": {
"$ref": "#/definitions/RedisConfig"
"description": "Any of: RedisConfigSentinel, RedisConfigSingle",
"anyOf": [
{
"$ref": "#/definitions/RedisConfigSentinel"
},
{
"$ref": "#/definitions/RedisConfigSingle"
}
]
}
}
},
Expand Down Expand Up @@ -73,10 +81,63 @@
}
}
},
"RedisConfig": {
"RedisConfigSentinel": {
"additionalProperties": false,
"type": "object",
"title": "RedisConfigSentinel",
"properties": {
"name": {
"type": "string",
"description": "identifies a group of Redis instances composed of a master and one or more slaves"
},
"sentinelPassword": {
"type": "string",
"description": "(optional) password for Sentinel instances."
},
"sentinels": {
"type": "array",
"items": {
"$ref": "#/definitions/RedisSentinelConfig"
},
"additionalItems": false,
"description": "A list of sentinels to connect to. The list does not need to enumerate all your sentinel instances, but a few so that if one is down the client will try the next one."
},
"role": {
"type": "string",
"enum": ["master", "slave"],
"description": "(optional) with a value of slave will return a random slave from the Sentinel group. (Allowed values: master, slave)"
},
"enableTLSForSentinelMode": {
"type": "boolean",
"description": "(optional) set to true if connecting to sentinel instances that are encrypted"
},
"lazyConnect": {
"type": "boolean",
"description": "Flag to indicate lazyConnect value for Redis client.\n\n@default: true"
}
},
"required": ["name", "sentinels"]
},
"RedisSentinelConfig": {
"additionalProperties": false,
"type": "object",
"title": "RedisSentinelConfig",
"properties": {
"host": {
"type": "string"
},
"port": {
"type": "string"
},
"family": {
"type": "string"
}
}
},
"RedisConfigSingle": {
"additionalProperties": false,
"type": "object",
"title": "RedisConfig",
"title": "RedisConfigSingle",
"properties": {
"host": {
"type": "string"
Expand All @@ -96,6 +157,9 @@
"url": {
"type": "string"
},
"family": {
"type": "string"
},
"lazyConnect": {
"type": "boolean",
"description": "Flag to indicate lazyConnect value for Redis client.\n\n@default: true"
Expand Down
41 changes: 39 additions & 2 deletions packages/legacy/types/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1801,7 +1801,10 @@ export interface Cache {
cfwKv?: CFWorkersKVCacheConfig;
file?: FileCacheConfig;
localforage?: LocalforageConfig;
redis?: RedisConfig;
/**
* Any of: RedisConfigSentinel, RedisConfigSingle
*/
redis?: RedisConfigSentinel | RedisConfigSingle;
[k: string]: any;
}
export interface CFWorkersKVCacheConfig {
Expand All @@ -1826,13 +1829,47 @@ export interface LocalforageConfig {
storeName?: string;
description?: string;
}
export interface RedisConfig {
export interface RedisConfigSentinel {
/**
* identifies a group of Redis instances composed of a master and one or more slaves
*/
name: string;
/**
* (optional) password for Sentinel instances.
*/
sentinelPassword?: string;
/**
* A list of sentinels to connect to. The list does not need to enumerate all your sentinel instances, but a few so that if one is down the client will try the next one.
*/
sentinels: RedisSentinelConfig[];
/**
* (optional) with a value of slave will return a random slave from the Sentinel group. (Allowed values: master, slave)
*/
role?: 'master' | 'slave';
/**
* (optional) set to true if connecting to sentinel instances that are encrypted
*/
enableTLSForSentinelMode?: boolean;
/**
* Flag to indicate lazyConnect value for Redis client.
*
* @default: true
*/
lazyConnect?: boolean;
}
export interface RedisSentinelConfig {
host?: string;
port?: string;
family?: string;
}
export interface RedisConfigSingle {
host?: string;
port?: string;
username?: string;
password?: string;
db?: number;
url?: string;
family?: string;
/**
* Flag to indicate lazyConnect value for Redis client.
*
Expand Down
10 changes: 9 additions & 1 deletion website/src/generated-markdown/RedisConfig.generated.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,12 @@
* `url` (type: `String`)
* `lazyConnect` (type: `Boolean`) - Flag to indicate lazyConnect value for Redis client.

@default: true
@default: true
* `name` (type: `String`) - identifies a group of Redis instances composed of a master and one or more slaves
* `sentinelPassword` (type: `String`) - (optional) password for Sentinel instances.
* `sentinels` (type: `Array of Object`) - A list of sentinels to connect to. The list does not need to enumerate all your sentinel instances, but a few so that if one is down the client will try the next one.:
* `host` (type: `String`)
* `port` (type: `String`)
* `role` (type: `String`) - (optional) with a value of slave will return a random slave from the Sentinel group.
* `preferredSlavbe` (type: `String`) - (optional) can be used to prefer a particular slave or set of slaves based on priority. It accepts a function or array.
* `enableTLSForSentinelMode` (type: `Boolean`) - (optional) set to true if connecting to sentinel instances that are encrypted
12 changes: 12 additions & 0 deletions website/src/generated-markdown/RedisConfigSentinel.generated.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

* `name` (type: `String`, required) - identifies a group of Redis instances composed of a master and one or more slaves
* `sentinelPassword` (type: `String`) - (optional) password for Sentinel instances.
* `sentinels` (type: `Array of Object`, required) - A list of sentinels to connect to. The list does not need to enumerate all your sentinel instances, but a few so that if one is down the client will try the next one.:
* `host` (type: `String`)
* `port` (type: `String`)
* `family` (type: `String`)
* `role` (type: `String (master | slave)`) - (optional) with a value of slave will return a random slave from the Sentinel group.
* `enableTLSForSentinelMode` (type: `Boolean`) - (optional) set to true if connecting to sentinel instances that are encrypted
* `lazyConnect` (type: `Boolean`) - Flag to indicate lazyConnect value for Redis client.

@default: true
11 changes: 11 additions & 0 deletions website/src/generated-markdown/RedisConfigSingle.generated.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

* `host` (type: `String`)
* `port` (type: `String`)
* `username` (type: `String`)
* `password` (type: `String`)
* `db` (type: `Int`)
* `url` (type: `String`)
* `family` (type: `String`)
* `lazyConnect` (type: `Boolean`) - Flag to indicate lazyConnect value for Redis client.

@default: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

* `host` (type: `String`)
* `port` (type: `String`)
* `family` (type: `String`)
Loading