Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1bb82f6
Add SentinelConnect and SentinelMasterConnect to ConnectionMultiplexe…
ejsmith Apr 13, 2020
6a6325c
Update configuration docs to show a sample of connecting to sentinel …
ejsmith Apr 13, 2020
6786a9e
Remove dead code
ejsmith Apr 13, 2020
e7e756a
Some progress, but moving over to Windows because dev on OSX doesn't …
ejsmith Apr 29, 2020
c3243d4
Get all tests passing
ejsmith Apr 30, 2020
891b4d2
Add some missing overloads and fix issue with connectasync with sentinel
ejsmith Apr 30, 2020
48c0a09
Sentinel doc update
ejsmith Apr 30, 2020
4276b53
Update docs/Configuration.md
ejsmith May 2, 2020
a32f611
Making suggested changed from @NickCraver
ejsmith May 2, 2020
6596378
More updates from feedback
ejsmith May 2, 2020
3a8a5d8
More config reverts
ejsmith May 2, 2020
ba2d939
Missed a spot for using sentinel parameter label.
ejsmith May 5, 2020
3557c76
More complete sentinel implementation. Add slaves to endpoints when c…
ejsmith May 7, 2020
e5f58ed
Make test more reliable
ejsmith May 8, 2020
9883862
Revert some unintended whitespace changes
ejsmith May 8, 2020
c8107e1
Couple small updates from feedback
ejsmith May 11, 2020
3017b81
Remove Role from IServer, wait for connect timeout
ejsmith May 12, 2020
495cd3e
Remove role from more spots. Cleanup tests and make them more reliabl…
ejsmith May 12, 2020
6ad3aec
Remove unused variable
ejsmith May 13, 2020
6e9e80e
Merge branch 'master' into pr/1431
Jun 8, 2020
4cd8faf
Merge bits
Jun 8, 2020
b606fae
More cleanup
Jun 8, 2020
91b1dbd
Dammit
Jun 8, 2020
ebdb395
Fix processor naming
Jun 8, 2020
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
9 changes: 9 additions & 0 deletions StackExchange.Redis.sln
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RedisConfigs", "RedisConfig
tests\RedisConfigs\cli-master.cmd = tests\RedisConfigs\cli-master.cmd
tests\RedisConfigs\cli-secure.cmd = tests\RedisConfigs\cli-secure.cmd
tests\RedisConfigs\cli-slave.cmd = tests\RedisConfigs\cli-slave.cmd
tests\RedisConfigs\docker-compose.yml = tests\RedisConfigs\docker-compose.yml
tests\RedisConfigs\Dockerfile = tests\RedisConfigs\Dockerfile
tests\RedisConfigs\start-all.cmd = tests\RedisConfigs\start-all.cmd
tests\RedisConfigs\start-all.sh = tests\RedisConfigs\start-all.sh
tests\RedisConfigs\start-basic.cmd = tests\RedisConfigs\start-basic.cmd
Expand Down Expand Up @@ -126,6 +128,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestConsoleBaseline", "toys
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = ".github", ".github\.github.csproj", "{8FB98E7D-DAE2-4465-BD9A-104000E0A2D4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docker", "Docker", "{A9F81DA3-DA82-423E-A5DD-B11C37548E06}"
ProjectSection(SolutionItems) = preProject
tests\RedisConfigs\Docker\docker-entrypoint.sh = tests\RedisConfigs\Docker\docker-entrypoint.sh
tests\RedisConfigs\Docker\supervisord.conf = tests\RedisConfigs\Docker\supervisord.conf
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -197,6 +205,7 @@ Global
{3DA1EEED-E9FE-43D9-B293-E000CFCCD91A} = {E25031D3-5C64-430D-B86F-697B66816FD8}
{153A10E4-E668-41AD-9E0F-6785CE7EED66} = {3AD17044-6BFF-4750-9AC2-2CA466375F2A}
{D58114AE-4998-4647-AFCA-9353D20495AE} = {E25031D3-5C64-430D-B86F-697B66816FD8}
{A9F81DA3-DA82-423E-A5DD-B11C37548E06} = {96E891CD-2ED7-4293-A7AB-4C6F5D8D2B05}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {193AA352-6748-47C1-A5FC-C9AA6B5F000B}
Expand Down
10 changes: 9 additions & 1 deletion docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ This will connect to a single server on the local machine using the default redi
var conn = ConnectionMultiplexer.Connect("redis0:6380,redis1:6380,allowAdmin=true");
```

If you specify a serviceName in the connection string, it will trigger sentinel mode. This example will connect to a sentinel server on the local machine
using the default sentinel port (26379), discover the current master server for the `mymaster` service and return a managed connection
pointing to that master server that will automatically be updated if the master changes:

```csharp
var conn = ConnectionMultiplexer.Connect("localhost,serviceName=mymaster");
```

An overview of mapping between the `string` and `ConfigurationOptions` representation is shown below, but you can switch between them trivially:

```csharp
Expand Down Expand Up @@ -79,7 +87,7 @@ The `ConfigurationOptions` object has a wide range of properties, all of which a
| proxy={proxy type} | `Proxy` | `Proxy.None` | Type of proxy in use (if any); for example "twemproxy" |
| resolveDns={bool} | `ResolveDns` | `false` | Specifies that DNS resolution should be explicit and eager, rather than implicit |
| responseTimeout={int} | `ResponseTimeout` | `SyncTimeout` | Time (ms) to decide whether the socket is unhealthy |
| serviceName={string} | `ServiceName` | `null` | Not currently implemented (intended for use with sentinel) |
| serviceName={string} | `ServiceName` | `null` | Used for connecting to a sentinel master service |
| ssl={bool} | `Ssl` | `false` | Specifies that SSL encryption should be used |
| sslHost={string} | `SslHost` | `null` | Enforces a particular SSL host identity on the server's certificate |
| sslProtocols={enum} | `SslProtocols` | `null` | Ssl/Tls versions supported when using an encrypted connection. Use '\|' to provide multiple values. |
Expand Down
273 changes: 229 additions & 44 deletions src/StackExchange.Redis/ConnectionMultiplexer.cs

Large diffs are not rendered by default.

22 changes: 21 additions & 1 deletion src/StackExchange.Redis/EndPointCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace StackExchange.Redis
/// <summary>
/// A list of endpoints
/// </summary>
public sealed class EndPointCollection : Collection<EndPoint>, IEnumerable, IEnumerable<EndPoint>
public sealed class EndPointCollection : Collection<EndPoint>, IEnumerable<EndPoint>
{
/// <summary>
/// Create a new EndPointCollection
Expand Down Expand Up @@ -59,6 +59,26 @@ public void Add(string hostAndPort)
/// <param name="port">The port for <paramref name="host"/> to add.</param>
public void Add(IPAddress host, int port) => Add(new IPEndPoint(host, port));

/// <summary>
/// Try adding a new endpoint to the list.
/// </summary>
/// <param name="endpoint">The endpoint to add.</param>
/// <returns>True if the endpoint was added or false if not.</returns>
public bool TryAdd(EndPoint endpoint)
{
if (endpoint == null) throw new ArgumentNullException(nameof(endpoint));

if (!Contains(endpoint))
{
base.InsertItem(Count, endpoint);
return true;
}
else
{
return false;
}
}

/// <summary>
/// See Collection&lt;T&gt;.InsertItem()
/// </summary>
Expand Down
31 changes: 29 additions & 2 deletions src/StackExchange.Redis/Interfaces/IServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -792,7 +792,7 @@ public partial interface IServer : IRedis
/// for the given service name.
/// </summary>
/// <param name="serviceName">the sentinel service name</param>
/// <param name="flags"></param>
/// <param name="flags">The command flags to use.</param>
/// <returns>a list of the sentinel ips and ports</returns>
EndPoint[] SentinelGetSentinelAddresses(string serviceName, CommandFlags flags = CommandFlags.None);

Expand All @@ -801,10 +801,28 @@ public partial interface IServer : IRedis
/// for the given service name.
/// </summary>
/// <param name="serviceName">the sentinel service name</param>
/// <param name="flags"></param>
/// <param name="flags">The command flags to use.</param>
/// <returns>a list of the sentinel ips and ports</returns>
Task<EndPoint[]> SentinelGetSentinelAddressesAsync(string serviceName, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns the ip and port numbers of all known Sentinel replicas
/// for the given service name.
/// </summary>
/// <param name="serviceName">the sentinel service name</param>
/// <param name="flags">The command flags to use.</param>
/// <returns>a list of the replica ips and ports</returns>
EndPoint[] SentinelGetReplicaAddresses(string serviceName, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Returns the ip and port numbers of all known Sentinel replicas
/// for the given service name.
/// </summary>
/// <param name="serviceName">the sentinel service name</param>
/// <param name="flags">The command flags to use.</param>
/// <returns>a list of the replica ips and ports</returns>
Task<EndPoint[]> SentinelGetReplicaAddressesAsync(string serviceName, CommandFlags flags = CommandFlags.None);

/// <summary>
/// Show the state and info of the specified master.
/// </summary>
Expand Down Expand Up @@ -1024,5 +1042,14 @@ internal static class IServerExtensions
/// </summary>
/// <param name="server">The server to simulate failure on.</param>
public static void SimulateConnectionFailure(this IServer server) => (server as RedisServer)?.SimulateConnectionFailure();

public static string Role(this IServer server)
{
var result = (RedisResult[])server.Execute("ROLE");
if (result != null && result.Length > 0)
return result[0].ToString();

return null;
}
}
}
2 changes: 2 additions & 0 deletions src/StackExchange.Redis/RedisLiterals.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,14 @@ public static readonly RedisValue

// misc (config, etc)
databases = "databases",
master = "master",
no = "no",
normal = "normal",
pubsub = "pubsub",
replica = "replica",
replica_read_only = "replica-read-only",
replication = "replication",
sentinel = "sentinel",
server = "server",
slave = "slave",
slave_read_only = "slave-read-only",
Expand Down
14 changes: 14 additions & 0 deletions src/StackExchange.Redis/RedisServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,18 @@ public Task<EndPoint[]> SentinelGetSentinelAddressesAsync(string serviceName, Co
return ExecuteAsync(msg, ResultProcessor.SentinelAddressesEndPoints);
}

public EndPoint[] SentinelGetReplicaAddresses(string serviceName, CommandFlags flags = CommandFlags.None)
{
var msg = Message.Create(-1, flags, RedisCommand.SENTINEL, RedisLiterals.SLAVES, (RedisValue)serviceName);
return ExecuteSync(msg, ResultProcessor.SentinelAddressesEndPoints);
}

public Task<EndPoint[]> SentinelGetReplicaAddressesAsync(string serviceName, CommandFlags flags = CommandFlags.None)
{
var msg = Message.Create(-1, flags, RedisCommand.SENTINEL, RedisLiterals.SLAVES, (RedisValue)serviceName);
return ExecuteAsync(msg, ResultProcessor.SentinelAddressesEndPoints);
}

public KeyValuePair<string, string>[] SentinelMaster(string serviceName, CommandFlags flags = CommandFlags.None)
{
var msg = Message.Create(-1, flags, RedisCommand.SENTINEL, RedisLiterals.MASTER, (RedisValue)serviceName);
Expand Down Expand Up @@ -866,6 +878,7 @@ public Task<KeyValuePair<string, string>[][]> SentinelMastersAsync(CommandFlags
return ExecuteAsync(msg, ResultProcessor.SentinelArrayOfArrays);
}

// For previous compat only
KeyValuePair<string, string>[][] IServer.SentinelSlaves(string serviceName, CommandFlags flags)
=> SentinelReplicas(serviceName, flags);

Expand All @@ -876,6 +889,7 @@ public KeyValuePair<string, string>[][] SentinelReplicas(string serviceName, Com
return ExecuteSync(msg, ResultProcessor.SentinelArrayOfArrays);
}

// For previous compat only
Task<KeyValuePair<string, string>[][]> IServer.SentinelSlavesAsync(string serviceName, CommandFlags flags)
=> SentinelReplicasAsync(serviceName, flags);

Expand Down
62 changes: 60 additions & 2 deletions src/StackExchange.Redis/ResultProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,10 @@ public static readonly ResultProcessor<EndPoint>
SentinelMasterEndpoint = new SentinelGetMasterAddressByNameProcessor();

public static readonly ResultProcessor<EndPoint[]>
SentinelAddressesEndPoints = new SentinelGetSentinelAddresses();
SentinelAddressesEndPoints = new SentinelGetSentinelAddressesProcessor();

public static readonly ResultProcessor<EndPoint[]>
SentinelReplicaEndPoints = new SentinelGetReplicaAddressesProcessor();

public static readonly ResultProcessor<KeyValuePair<string, string>[][]>
SentinelArrayOfArrays = new SentinelArrayOfArraysProcessor();
Expand Down Expand Up @@ -2036,7 +2039,62 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes
}
}

private sealed class SentinelGetSentinelAddresses : ResultProcessor<EndPoint[]>
private sealed class SentinelGetSentinelAddressesProcessor : ResultProcessor<EndPoint[]>
{
protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result)
{
List<EndPoint> endPoints = new List<EndPoint>();

switch (result.Type)
{
case ResultType.MultiBulk:
foreach (RawResult item in result.GetItems())
{
var arr = item.GetItemsAsValues();
string ip = null;
string portStr = null;

for (int i = 0; i < arr.Length && (ip == null || portStr == null); i += 2)
{
string name = arr[i];
string value = arr[i + 1];

switch (name)
{
case "ip":
ip = value;
break;
case "port":
portStr = value;
break;
}
}

if (ip != null && portStr != null && int.TryParse(portStr, out int port))
{
endPoints.Add(Format.ParseEndPoint(ip, port));
}
}
break;

case ResultType.SimpleString:
//We don't want to blow up if the master is not found
if (result.IsNull)
return true;
break;
}

if (endPoints.Count > 0)
{
SetResult(message, endPoints.ToArray());
return true;
}

return false;
}
}

private sealed class SentinelGetReplicaAddressesProcessor : ResultProcessor<EndPoint[]>
{
protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result)
{
Expand Down
2 changes: 1 addition & 1 deletion tests/RedisConfigs/Docker/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ if [ "$#" -ne 0 ]; then
exec "$@"
else
mkdir -p /var/log/supervisor
mkdir Temp/
mkdir -p Temp/

supervisord -c /etc/supervisord.conf
sleep 3
Expand Down
Loading