forked from kurrent-io/KurrentDB
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathConnectionSettingsBuilder.cs
459 lines (410 loc) · 18.1 KB
/
ConnectionSettingsBuilder.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
using System;
using System.Linq;
using System.Net;
using EventStore.ClientAPI.Common.Log;
using EventStore.ClientAPI.Common.Utils;
using EventStore.ClientAPI.SystemData;
namespace EventStore.ClientAPI
{
/// <summary>
/// Used to build a connection settings (fluent API)
/// </summary>
public class ConnectionSettingsBuilder
{
private ILogger _log = new NoopLogger();
private bool _verboseLogging;
private int _maxQueueSize = Consts.DefaultMaxQueueSize;
private int _maxConcurrentItems = Consts.DefaultMaxConcurrentItems;
private int _maxRetries = Consts.DefaultMaxOperationRetries;
private int _maxReconnections = Consts.DefaultMaxReconnections;
private bool _requireMaster = Consts.DefaultRequireMaster;
private TimeSpan _reconnectionDelay = Consts.DefaultReconnectionDelay;
private TimeSpan _operationTimeout = Consts.DefaultOperationTimeout;
private TimeSpan _operationTimeoutCheckPeriod = Consts.DefaultOperationTimeoutCheckPeriod;
private UserCredentials _defaultUserCredentials;
private bool _useSslConnection;
private string _targetHost;
private bool _validateServer;
private bool _failOnNoServerResponse;
private TimeSpan _heartbeatInterval = TimeSpan.FromMilliseconds(750);
private TimeSpan _heartbeatTimeout = TimeSpan.FromMilliseconds(1500);
private TimeSpan _clientConnectionTimeout = TimeSpan.FromMilliseconds(1000);
private string _clusterDns;
private int _maxDiscoverAttempts = Consts.DefaultMaxClusterDiscoverAttempts;
private int _gossipExternalHttpPort = Consts.DefaultClusterManagerExternalHttpPort;
private TimeSpan _gossipTimeout = TimeSpan.FromSeconds(1);
private GossipSeed[] _gossipSeeds;
private bool _preferRandomNode = false;
internal ConnectionSettingsBuilder()
{
}
/// <summary>
/// Configures the connection to output log messages to the given <see cref="ILogger" />.
/// </summary>
/// <param name="logger">The <see cref="ILogger"/> to use.</param>
/// <returns></returns>
public ConnectionSettingsBuilder UseCustomLogger(ILogger logger)
{
Ensure.NotNull(logger, "logger");
_log = logger;
return this;
}
/// <summary>
/// Configures the connection to output log messages to the console.
/// </summary>
public ConnectionSettingsBuilder UseConsoleLogger()
{
_log = new ConsoleLogger();
return this;
}
/// <summary>
/// Configures the connection to output log messages to the listeners
/// configured on <see cref="System.Diagnostics.Debug" />.
/// </summary>
public ConnectionSettingsBuilder UseDebugLogger()
{
_log = new DebugLogger();
return this;
}
/// <summary>
/// Configures the connection to output log messages to a file.
/// </summary>
public ConnectionSettingsBuilder UseFileLogger(string filename)
{
_log = new FileLogger(filename);
return this;
}
/// <summary>
/// Turns on verbose <see cref="EventStoreConnection"/> internal logic logging.
/// </summary>
/// <returns></returns>
public ConnectionSettingsBuilder EnableVerboseLogging()
{
_verboseLogging = true;
return this;
}
/// <summary>
/// Sets the limit for number of outstanding operations
/// </summary>
/// <param name="limit">The new limit of outstanding operations</param>
/// <returns></returns>
public ConnectionSettingsBuilder LimitOperationsQueueTo(int limit)
{
Ensure.Positive(limit, "limit");
_maxQueueSize = limit;
return this;
}
/// <summary>
/// Limits the number of concurrent operations that this connection can have
/// </summary>
/// <param name="limit"></param>
/// <returns></returns>
public ConnectionSettingsBuilder LimitConcurrentOperationsTo(int limit)
{
Ensure.Positive(limit, "limit");
_maxConcurrentItems = limit;
return this;
}
/// <summary>
/// Limits the number of operation attempts
/// </summary>
/// <param name="limit"></param>
/// <returns></returns>
public ConnectionSettingsBuilder LimitAttemptsForOperationTo(int limit)
{
Ensure.Positive(limit, "limit");
_maxRetries = limit - 1;
return this;
}
/// <summary>
/// Limits the number of operation retries
/// </summary>
/// <param name="limit"></param>
/// <returns></returns>
public ConnectionSettingsBuilder LimitRetriesForOperationTo(int limit)
{
Ensure.Nonnegative(limit, "limit");
_maxRetries = limit;
return this;
}
/// <summary>
/// Allows infinite operation retry attempts
/// </summary>
/// <returns></returns>
public ConnectionSettingsBuilder KeepRetrying()
{
_maxRetries = -1;
return this;
}
/// <summary>
/// Limits the number of reconnections this connection can try to make
/// </summary>
/// <param name="limit"></param>
/// <returns></returns>
public ConnectionSettingsBuilder LimitReconnectionsTo(int limit)
{
Ensure.Nonnegative(limit, "limit");
_maxReconnections = limit;
return this;
}
/// <summary>
/// Allows infinite reconnection attempts
/// </summary>
/// <returns></returns>
public ConnectionSettingsBuilder KeepReconnecting()
{
_maxReconnections = -1;
return this;
}
/// <summary>
/// Requires all write and read requests to be served only by master (cluster version only)
/// </summary>
/// <returns></returns>
public ConnectionSettingsBuilder PerformOnMasterOnly()
{
_requireMaster = true;
return this;
}
/// <summary>
/// Allow for writes to be forwarded and read requests served locally if node is not master (cluster version only)
/// </summary>
/// <returns></returns>
public ConnectionSettingsBuilder PerformOnAnyNode()
{
_requireMaster = false;
return this;
}
/// <summary>
/// Sets the delay between reconnection attempts
/// </summary>
/// <param name="reconnectionDelay"></param>
/// <returns></returns>
public ConnectionSettingsBuilder SetReconnectionDelayTo(TimeSpan reconnectionDelay)
{
_reconnectionDelay = reconnectionDelay;
return this;
}
/// <summary>
/// Sets the operation timeout duration
/// </summary>
/// <param name="operationTimeout"></param>
/// <returns></returns>
public ConnectionSettingsBuilder SetOperationTimeoutTo(TimeSpan operationTimeout)
{
_operationTimeout = operationTimeout;
return this;
}
/// <summary>
/// Sets how often timeouts should be checked for.
/// </summary>
/// <param name="timeoutCheckPeriod"></param>
/// <returns></returns>
public ConnectionSettingsBuilder SetTimeoutCheckPeriodTo(TimeSpan timeoutCheckPeriod)
{
_operationTimeoutCheckPeriod = timeoutCheckPeriod;
return this;
}
/// <summary>
/// Sets the default <see cref="UserCredentials"/> to be used for this connection.
/// If user credentials are not given for an operation, these credentials will be used.
/// </summary>
/// <param name="userCredentials"></param>
/// <returns></returns>
public ConnectionSettingsBuilder SetDefaultUserCredentials(UserCredentials userCredentials)
{
_defaultUserCredentials = userCredentials;
return this;
}
/// <summary>
/// Uses a SSL connection over TCP. This should generally be used with authentication.
/// </summary>
/// <param name="targetHost">HostName of server certificate.</param>
/// <param name="validateServer">Whether to accept connection from server with not trusted certificate.</param>
/// <returns></returns>
public ConnectionSettingsBuilder UseSslConnection(string targetHost, bool validateServer)
{
Ensure.NotNullOrEmpty(targetHost, "targetHost");
_useSslConnection = true;
_targetHost = targetHost;
_validateServer = validateServer;
return this;
}
/// <summary>
/// Marks that no response from server should cause an error on the request
/// </summary>
/// <returns></returns>
public ConnectionSettingsBuilder FailOnNoServerResponse()
{
_failOnNoServerResponse = true;
return this;
}
/// <summary>
/// Sets how often heartbeats should be expected on the connection (lower values detect broken sockets faster)
/// </summary>
/// <param name="interval"></param>
/// <returns></returns>
public ConnectionSettingsBuilder SetHeartbeatInterval(TimeSpan interval)
{
_heartbeatInterval = interval;
return this;
}
/// <summary>
/// Sets how long to wait without heartbeats before determining a connection to be dead (must be longer than heartbeat interval)
/// </summary>
/// <param name="timeout"></param>
/// <returns></returns>
public ConnectionSettingsBuilder SetHeartbeatTimeout(TimeSpan timeout)
{
_heartbeatTimeout = timeout;
return this;
}
/// <summary>
/// Sets the timeout for attempting to connect to a server before aborting and attempting a reconnect.
/// </summary>
/// <param name="timeout"></param>
/// <returns></returns>
public ConnectionSettingsBuilder WithConnectionTimeoutOf(TimeSpan timeout)
{
_clientConnectionTimeout = timeout;
return this;
}
/// <summary>
/// Sets the DNS name under which cluster nodes are listed.
/// </summary>
/// <param name="clusterDns">The DNS name under which cluster nodes are listed.</param>
/// <returns>A <see cref="DnsClusterSettingsBuilder"/> for further configuration.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="clusterDns" /> is null or empty.</exception>
public ConnectionSettingsBuilder SetClusterDns(string clusterDns)
{
Ensure.NotNullOrEmpty(clusterDns, "clusterDns");
_clusterDns = clusterDns;
return this;
}
/// <summary>
/// Sets the maximum number of attempts for discovery.
/// </summary>
/// <param name="maxDiscoverAttempts">The maximum number of attempts for DNS discovery.</param>
/// <returns>A <see cref="DnsClusterSettingsBuilder"/> for further configuration.</returns>
/// <exception cref="ArgumentOutOfRangeException">If <paramref name="maxDiscoverAttempts" /> is less than or equal to 0.</exception>
public ConnectionSettingsBuilder SetMaxDiscoverAttempts(int maxDiscoverAttempts)
{
if (maxDiscoverAttempts <= 0)
throw new ArgumentOutOfRangeException("maxDiscoverAttempts", string.Format("maxDiscoverAttempts value is out of range: {0}. Allowed range: [1, infinity].", maxDiscoverAttempts));
_maxDiscoverAttempts = maxDiscoverAttempts;
return this;
}
/// <summary>
/// Sets the period after which gossip times out if none is received.
/// </summary>
/// <param name="timeout">The period after which gossip times out if none is received.</param>
/// <returns>A <see cref="DnsClusterSettingsBuilder"/> for further configuration.</returns>
public ConnectionSettingsBuilder SetGossipTimeout(TimeSpan timeout)
{
_gossipTimeout = timeout;
return this;
}
/// <summary>
/// Whether to randomly choose a node that's alive from the known nodes.
/// </summary>
/// <returns>A <see cref="DnsClusterSettingsBuilder"/> for further configuration.</returns>
public ConnectionSettingsBuilder PreferRandomNode()
{
_preferRandomNode = true;
return this;
}
/// <summary>
/// Sets the well-known port on which the cluster gossip is taking place.
///
/// If you are using the commercial edition of Event Store HA, with Manager nodes in
/// place, this should be the port number of the External HTTP port on which the
/// managers are running.
///
/// If you are using the open source edition of Event Store HA, this should be the
/// External HTTP port that the nodes are running on. If you cannot use a well-known
/// port for this across all nodes, you can instead use gossip seed discovery and set
/// the <see cref="IPEndPoint" /> of some seed nodes instead.
/// </summary>
/// <param name="clusterGossipPort">The cluster gossip port.</param>
/// <returns>A <see cref="DnsClusterSettingsBuilder"/> for further configuration.</returns>
public ConnectionSettingsBuilder SetClusterGossipPort(int clusterGossipPort)
{
Ensure.Positive(clusterGossipPort, "clusterGossipPort");
_gossipExternalHttpPort = clusterGossipPort;
return this;
}
/// <summary>
/// Sets gossip seed endpoints for the client.
///
/// Note that this should be the external HTTP endpoint of the server, as it is required
/// for the client to exchange gossip with the server. The standard port which should be
/// used here is 2113.
///
/// If the server requires a specific Host header to be sent as part of the gossip
/// request, use the overload of this method taking <see cref="GossipSeed" /> instead.
/// </summary>
/// <param name="gossipSeeds"><see cref="IPEndPoint" />s representing the endpoints of nodes from which to seed gossip.</param>
/// <returns>A <see cref="ClusterSettingsBuilder"/> for further configuration.</returns>
/// <exception cref="ArgumentException">If no gossip seeds are specified.</exception>
public ConnectionSettingsBuilder SetGossipSeedEndPoints(params IPEndPoint[] gossipSeeds)
{
if (gossipSeeds == null || gossipSeeds.Length == 0)
throw new ArgumentException("Empty FakeDnsEntries collection.");
_gossipSeeds = gossipSeeds.Select(x => new GossipSeed(x)).ToArray();
return this;
}
/// <summary>
/// Sets gossip seed endpoints for the client.
/// </summary>
/// <param name="gossipSeeds"><see cref="GossipSeed"/>s representing the endpoints of nodes from which to seed gossip.</param>
/// <returns>A <see cref="ClusterSettingsBuilder"/> for further configuration.</returns>
/// <exception cref="ArgumentException">If no gossip seeds are specified.</exception>
public ConnectionSettingsBuilder SetGossipSeedEndPoints(params GossipSeed[] gossipSeeds)
{
if (gossipSeeds == null || gossipSeeds.Length == 0)
throw new ArgumentException("Empty FakeDnsEntries collection.");
_gossipSeeds = gossipSeeds;
return this;
}
/// <summary>
/// Convert the mutable <see cref="ConnectionSettingsBuilder"/> object to an immutable
/// <see cref="ConnectionSettings"/> object.
/// </summary>
/// <param name="builder">The <see cref="ConnectionSettingsBuilder"/> to convert.</param>
/// <returns>An immutable <see cref="ConnectionSettings"/> object with the values specified by the builder.</returns>
public static implicit operator ConnectionSettings(ConnectionSettingsBuilder builder)
{
return builder.Build();
}
/// <summary>
/// Convert the mutable <see cref="ConnectionSettingsBuilder"/> object to an immutable
/// <see cref="ConnectionSettings"/> object.
/// </summary>
public ConnectionSettings Build()
{
return new ConnectionSettings(_log,
_verboseLogging,
_maxQueueSize,
_maxConcurrentItems,
_maxRetries,
_maxReconnections,
_requireMaster,
_reconnectionDelay,
_operationTimeout,
_operationTimeoutCheckPeriod,
_defaultUserCredentials,
_useSslConnection,
_targetHost,
_validateServer,
_failOnNoServerResponse,
_heartbeatInterval,
_heartbeatTimeout,
_clientConnectionTimeout,
_clusterDns,
_gossipSeeds,
_maxDiscoverAttempts,
_gossipExternalHttpPort,
_gossipTimeout,
_preferRandomNode);
}
}
}