@@ -23,6 +23,11 @@ const INTEGRATION_MODE = Object.freeze({
2323 LOCAL_REDIS : "LOCAL_REDIS" ,
2424 NO_REDIS : "NO_REDIS" ,
2525} ) ;
26+ const CLIENT_NAME = Object . freeze ( {
27+ SILENT : "SILENT" ,
28+ MAIN : "MAIN" ,
29+ SUBSCRIBER : "SUBSCRIBER" ,
30+ } ) ;
2631const CF_REDIS_SERVICE_LABEL = "redis-cache" ;
2732const REDIS_CLIENT_DEFAULT_PING_INTERVAL = 4 * 60000 ;
2833
@@ -88,10 +93,6 @@ const _getRedisOptionsTuple = () => {
8893 if ( ! __activeOptionsTuple ) {
8994 const defaultClientOptions = {
9095 pingInterval : REDIS_CLIENT_DEFAULT_PING_INTERVAL ,
91- socket : {
92- host : "localhost" ,
93- port : 6379 ,
94- } ,
9596 } ;
9697
9798 const credentials = __customCredentials || cfEnv . cfServiceCredentialsForLabel ( CF_REDIS_SERVICE_LABEL ) ;
@@ -100,11 +101,11 @@ const _getRedisOptionsTuple = () => {
100101 const isCluster = ! ! credentials . cluster_mode ;
101102 const credentialClientOptions = hasCredentials
102103 ? {
103- password : credentials . password ,
104+ ... ( Object . prototype . hasOwnProperty . call ( credentials , " password" ) && { password : credentials . password } ) ,
104105 socket : {
105- host : credentials . hostname ,
106- port : credentials . port ,
107- tls : credentials . tls ,
106+ ... ( Object . prototype . hasOwnProperty . call ( credentials , "hostname" ) && { host : credentials . hostname } ) ,
107+ ... ( Object . prototype . hasOwnProperty . call ( credentials , " port" ) && { port : credentials . port } ) ,
108+ ... ( Object . prototype . hasOwnProperty . call ( credentials , " tls" ) && { tls : credentials . tls } ) ,
108109 } ,
109110 }
110111 : undefined ;
@@ -140,18 +141,28 @@ const _getRedisOptionsTuple = () => {
140141 return __activeOptionsTuple ;
141142} ;
142143
144+ const _noReconnectStrategy = ( ) => new VError ( { name : VERROR_CLUSTER_NAME } , "disabled reconnect" ) ;
145+
143146/**
144147 * Lazily create a new redis client. Client creation transparently handles
145148 * - custom credentials and client options passed in via {@link setCustomOptions},
146149 * - Cloud Foundry service with label "redis-cache" (hyperscaler option), and
147150 * - local redis-server.
148151 *
152+ * @param {string } clientName
153+ * @param {CreateOptions } [options]
149154 * @returns {RedisClient|RedisCluster }
150155 * @private
151156 */
152- const _createClientBase = ( clientName ) => {
157+ const _createClientBase = ( clientName , options = { } ) => {
158+ const { doReconnect = true } = options ;
153159 try {
154160 const [ isCluster , redisClientOptions ] = _getRedisOptionsTuple ( ) ;
161+
162+ if ( ! doReconnect ) {
163+ redisClientOptions . socket . reconnectStrategy = _noReconnectStrategy ;
164+ }
165+
155166 return isCluster
156167 ? redis . createCluster ( {
157168 rootNodes : [ redisClientOptions ] , // NOTE: assume this ignores everything but socket/url
@@ -167,10 +178,21 @@ const _createClientBase = (clientName) => {
167178 }
168179} ;
169180
170- const _createClientAndConnect = async ( clientName , { doLogEvents = true } = { } ) => {
181+ /**
182+ * @typedef CreateOptions
183+ * @type object
184+ * @property {boolean } [doLogEvents] log error events, defaults to true
185+ * @property {boolean } [doReconnect] setting to false disables reconnect strategy, defaults to true
186+ */
187+ /**
188+ * @param {string } clientName
189+ * @param {CreateOptions } [options]
190+ */
191+ const _createClientAndConnect = async ( clientName , options = { } ) => {
192+ const { doLogEvents = true } = options ;
171193 let client = null ;
172194 try {
173- client = _createClientBase ( clientName ) ;
195+ client = _createClientBase ( clientName , options ) ;
174196 } catch ( err ) {
175197 throw new VError ( { name : VERROR_CLUSTER_NAME , cause : err , info : { clientName } } , "error during create client" ) ;
176198 }
@@ -210,7 +232,10 @@ const _canGetClient = async () => {
210232 if ( __canGetClientPromise === null ) {
211233 __canGetClientPromise = ( async ( ) => {
212234 try {
213- const silentClient = await _createClientAndConnect ( "silent" , { doLogEvents : false } ) ;
235+ const silentClient = await _createClientAndConnect ( CLIENT_NAME . SILENT , {
236+ doLogEvents : false ,
237+ doReconnect : false ,
238+ } ) ;
214239 await _closeClientBase ( silentClient ) ;
215240 return true ;
216241 } catch { } // eslint-disable-line no-empty
@@ -251,7 +276,7 @@ const getIntegrationMode = async () => {
251276 */
252277const getMainClient = async ( ) => {
253278 if ( ! __mainClientPromise ) {
254- __mainClientPromise = _createClientAndConnect ( "main" ) ;
279+ __mainClientPromise = _createClientAndConnect ( CLIENT_NAME . MAIN ) ;
255280 }
256281 return await __mainClientPromise ;
257282} ;
@@ -277,7 +302,7 @@ const closeMainClient = async () => {
277302 */
278303const getSubscriberClient = async ( ) => {
279304 if ( ! __subscriberClientPromise ) {
280- __subscriberClientPromise = _createClientAndConnect ( "subscriber" ) ;
305+ __subscriberClientPromise = _createClientAndConnect ( CLIENT_NAME . SUBSCRIBER ) ;
281306 }
282307 return await __subscriberClientPromise ;
283308} ;
0 commit comments