-
-
Notifications
You must be signed in to change notification settings - Fork 177
/
RedisConfiguration.cs
486 lines (417 loc) · 13 KB
/
RedisConfiguration.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
// Copyright (c) Ugo Lattanzi. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Net.Security;
using System.Security.Authentication;
using Microsoft.Extensions.Logging;
using StackExchange.Redis.Extensions.Core.Abstractions;
using StackExchange.Redis.Extensions.Core.Implementations;
using StackExchange.Redis.Extensions.Core.Models;
using StackExchange.Redis.Profiling;
namespace StackExchange.Redis.Extensions.Core.Configuration;
/// <summary>
/// The redis configuration
/// </summary>
public class RedisConfiguration
{
private ConfigurationOptions? options;
private string keyPrefix = string.Empty;
private string? user;
private string? password;
private bool allowAdmin;
private bool ssl;
private int connectTimeout = 5000;
private int syncTimeout = 1000;
private bool abortOnConnectFail;
private int database;
private RedisHost[] hosts = Array.Empty<RedisHost>();
private ServerEnumerationStrategy serverEnumerationStrategy = new();
private uint maxValueLength;
private int poolSize = 5;
private string[]? excludeCommands;
private string? configurationChannel;
private string? connectionString;
private string? serviceName;
private int? connectRetry;
private SslProtocols? sslProtocols;
private Func<ProfilingSession>? profilingSessionProvider;
private int workCount = Environment.ProcessorCount * 2;
private ConnectionSelectionStrategy connectionSelectionStrategy = ConnectionSelectionStrategy.LeastLoaded;
private ILoggerFactory? loggerFactory;
private SocketManager.SocketManagerOptions socketManagerOptions = SocketManager.SocketManagerOptions.None;
/// <summary>
/// A RemoteCertificateValidationCallback delegate responsible for validating the certificate supplied by the remote party; note
/// that this cannot be specified in the configuration-string.
/// </summary>
public event RemoteCertificateValidationCallback? CertificateValidation;
/// <summary>
/// Indicate if the current configuration is the default;
/// </summary>
public bool IsDefault { get; set; }
/// <summary>
/// The identifier name for the connection
/// </summary>
public string? Name { get; set; }
/// <summary>
/// Gets or sets the every ConnectionSelectionStrategy to use during connection selection.
/// </summary>
public ConnectionSelectionStrategy ConnectionSelectionStrategy
{
get => connectionSelectionStrategy;
set
{
connectionSelectionStrategy = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets the every ConnectionMultiplexer SocketManager WorkCount
/// </summary>
public int WorkCount
{
get => workCount;
set
{
workCount = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// The number of times to repeat the initial connect cycle if no servers respond promptly.
/// </summary>
public int? ConnectRetry
{
get => connectRetry;
set
{
connectRetry = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets the servicename used in case of Sentinel.
/// </summary>
public string? ServiceName
{
get => serviceName;
set
{
serviceName = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets a value indicating whether get a boolean value that indicates if the cluster is configured for sentinel or not
/// </summary>
public bool IsSentinelCluster => !string.IsNullOrEmpty(ServiceName);
/// <summary>
/// Gets or sets the connection string. In wins over property configuration.
/// </summary>
public SslProtocols? SslProtocols
{
get => sslProtocols;
set
{
sslProtocols = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets the connection string. In wins over property configuration.
/// </summary>
public string? ConnectionString
{
get => connectionString;
set
{
connectionString = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets the channel to use for broadcasting and listening for configuration change notification.
/// </summary>
public string? ConfigurationChannel
{
get => configurationChannel;
set
{
configurationChannel = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets the key separation prefix used for all cache entries.
/// </summary>
public string KeyPrefix
{
get => keyPrefix;
set
{
keyPrefix = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets the redis user.
/// </summary>
public string? User
{
get => user;
set
{
user = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets the redis password.
/// </summary>
public string? Password
{
get => password;
set
{
password = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets a value indicating whether gets or sets whether admin operations should be allowed.
/// </summary>
public bool AllowAdmin
{
get => allowAdmin;
set
{
allowAdmin = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets a value indicating whether specify if whether the connection should be encrypted.
/// </summary>
public bool Ssl
{
get => ssl;
set
{
ssl = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets the time in milliseconds that should be allowed for connection (defaults to 5 seconds unless SyncTimeout is higher).
/// </summary>
public int ConnectTimeout
{
get => connectTimeout;
set
{
connectTimeout = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets the time in milliseconds that the system should allow for synchronous operations (defaults to 5 seconds).
/// </summary>
public int SyncTimeout
{
get => syncTimeout;
set
{
syncTimeout = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets a value indicating whether gets or sets whether connect/configuration timeouts should be explicitly notified via a TimeoutException.
/// </summary>
public bool AbortOnConnectFail
{
get => abortOnConnectFail;
set
{
abortOnConnectFail = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets database Id.
/// </summary>
public int Database
{
get => database;
set
{
database = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets the host of Redis Servers (The ips or names).
/// </summary>
public RedisHost[] Hosts
{
get => hosts;
set
{
hosts = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets the strategy to use when executing server wide commands.
/// </summary>
public ServerEnumerationStrategy ServerEnumerationStrategy
{
get => serverEnumerationStrategy;
set
{
serverEnumerationStrategy = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets maximal value length which can be set in database.
/// </summary>
public uint MaxValueLength
{
get => maxValueLength;
set
{
maxValueLength = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets redis connections pool size.
/// </summary>
public int PoolSize
{
get => poolSize;
set
{
poolSize = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets exclude commands.
/// </summary>
public string[]? ExcludeCommands
{
get => excludeCommands;
set
{
excludeCommands = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets redis Profiler to attach to ConnectionMultiplexer.
/// </summary>
public Func<ProfilingSession>? ProfilingSessionProvider
{
get => profilingSessionProvider;
set
{
profilingSessionProvider = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets redis LoggerFactory for using it with ConnectionMultiplexer and RedisConnectionPoolManager if logger not specified for last one.
/// </summary>
public ILoggerFactory? LoggerFactory
{
get => loggerFactory;
set
{
loggerFactory = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets redis SocketManagerOptions to attach to ConnectionMultiplexer.
/// </summary>
public SocketManager.SocketManagerOptions SocketManagerOptions
{
get => socketManagerOptions;
set
{
socketManagerOptions = value;
ResetConfigurationOptions();
}
}
/// <summary>
/// Gets or sets the factory for <see cref="IStateAwareConnection"/> creation
/// </summary>
/// <returns>>If property is not set, default <see cref="IStateAwareConnection"/> will be resolved</returns>
/// <remarks>
/// Proprerty is optional.
/// Property should be assined by invocation code only once. (We are not doing additional checks in the property itself in order to prevent any possible issues during serialization)
/// </remarks>
public StateAwareConnectionResolver StateAwareConnectionFactory { get; set; } = (cm, logger) => new RedisConnectionPoolManager.StateAwareConnection(cm, logger);
/// <summary>
/// Gets the Redis configuration options
/// </summary>
/// <value>An instanfe of <see cref="ConfigurationOptions" />.</value>
public ConfigurationOptions ConfigurationOptions
{
get
{
if (options == null)
{
ConfigurationOptions newOptions;
if (ConnectionString?.Length > 0)
{
newOptions = ConfigurationOptions.Parse(ConnectionString);
}
else
{
newOptions = new()
{
Ssl = Ssl,
AllowAdmin = AllowAdmin,
Password = Password,
ConnectTimeout = ConnectTimeout,
SyncTimeout = SyncTimeout,
AbortOnConnectFail = AbortOnConnectFail,
ConfigurationChannel = ConfigurationChannel!,
SslProtocols = sslProtocols,
ChannelPrefix = new RedisChannel(KeyPrefix, RedisChannel.PatternMode.Auto),
User = User
};
if (ConnectRetry != null)
newOptions.ConnectRetry = ConnectRetry.Value;
if (IsSentinelCluster)
{
newOptions.ServiceName = ServiceName;
newOptions.CommandMap = CommandMap.Sentinel;
}
foreach (var redisHost in Hosts)
newOptions.EndPoints.Add(redisHost.Host, redisHost.Port);
}
if (ExcludeCommands != null)
{
newOptions.CommandMap = CommandMap.Create(
[.. ExcludeCommands],
false);
}
if (LoggerFactory != null)
newOptions.LoggerFactory = LoggerFactory;
if (WorkCount > 0 || SocketManagerOptions != SocketManager.SocketManagerOptions.None)
newOptions.SocketManager = new(GetType().Name, WorkCount, SocketManagerOptions);
newOptions.CertificateValidation += CertificateValidation;
options = newOptions;
}
return options;
}
}
private void ResetConfigurationOptions()
{
// this is needed in order to cover this scenario
// https://github.com/imperugo/StackExchange.Redis.Extensions/issues/165
options = null;
}
}