More redis tweaks
- Implemented the task queue - Only subscribe to user channel if authenticated
This commit is contained in:
parent
ed41672381
commit
23eb8aa7bd
|
|
@ -36,18 +36,20 @@ namespace Microsoft.AspNetCore.SignalR.Redis
|
||||||
_redisServerConnection = _options.Connect(writer);
|
_redisServerConnection = _options.Connect(writer);
|
||||||
_bus = _redisServerConnection.GetSubscriber();
|
_bus = _redisServerConnection.GetSubscriber();
|
||||||
|
|
||||||
_bus.Subscribe(typeof(THub).FullName, (c, data) =>
|
var previousBroadcastTask = Task.CompletedTask;
|
||||||
|
|
||||||
|
_bus.Subscribe(typeof(THub).FullName, async (c, data) =>
|
||||||
{
|
{
|
||||||
|
await previousBroadcastTask;
|
||||||
|
|
||||||
var tasks = new List<Task>(_connections.Count);
|
var tasks = new List<Task>(_connections.Count);
|
||||||
|
|
||||||
// TODO: serialize once per format by providing a different stream?
|
|
||||||
foreach (var connection in _connections)
|
foreach (var connection in _connections)
|
||||||
{
|
{
|
||||||
tasks.Add(connection.Channel.Output.WriteAsync((byte[])data));
|
tasks.Add(connection.Channel.Output.WriteAsync((byte[])data));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Task Queue
|
previousBroadcastTask = Task.WhenAll(tasks);
|
||||||
Task.WhenAll(tasks).GetAwaiter().GetResult();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,43 +113,56 @@ namespace Microsoft.AspNetCore.SignalR.Redis
|
||||||
|
|
||||||
public override Task OnConnectedAsync(Connection connection)
|
public override Task OnConnectedAsync(Connection connection)
|
||||||
{
|
{
|
||||||
|
var redisSubscriptions = connection.Metadata.GetOrAdd("redis_subscriptions", _ => new HashSet<string>());
|
||||||
|
var connectionTask = Task.CompletedTask;
|
||||||
|
var userTask = Task.CompletedTask;
|
||||||
|
|
||||||
_connections.Add(connection);
|
_connections.Add(connection);
|
||||||
|
|
||||||
var connectionChannel = typeof(THub).FullName + "." + connection.ConnectionId;
|
var connectionChannel = typeof(THub).FullName + "." + connection.ConnectionId;
|
||||||
var userChannel = typeof(THub).FullName + "." + connection.User.Identity.Name;
|
|
||||||
|
|
||||||
var task1 = _bus.SubscribeAsync(connectionChannel, (c, data) =>
|
|
||||||
{
|
|
||||||
// TODO: serialize once per format by providing a different stream?
|
|
||||||
// TODO: Task Queue
|
|
||||||
connection.Channel.Output.WriteAsync((byte[])data).GetAwaiter().GetResult();
|
|
||||||
});
|
|
||||||
|
|
||||||
var task2 = _bus.SubscribeAsync(userChannel, (c, data) =>
|
|
||||||
{
|
|
||||||
// TODO: serialize once per format by providing a different stream?
|
|
||||||
// TODO: Task Queue
|
|
||||||
// TODO: Look at optimizing (looping over connections checking for Name)
|
|
||||||
connection.Channel.Output.WriteAsync((byte[])data).GetAwaiter().GetResult();
|
|
||||||
});
|
|
||||||
|
|
||||||
var redisSubscriptions = connection.Metadata.GetOrAdd("redis_subscriptions", _ => new HashSet<string>());
|
|
||||||
redisSubscriptions.Add(connectionChannel);
|
redisSubscriptions.Add(connectionChannel);
|
||||||
redisSubscriptions.Add(userChannel);
|
|
||||||
|
|
||||||
return Task.WhenAll(task1, task2);
|
var previousConnectionTask = Task.CompletedTask;
|
||||||
|
|
||||||
|
connectionTask = _bus.SubscribeAsync(connectionChannel, async (c, data) =>
|
||||||
|
{
|
||||||
|
await previousConnectionTask;
|
||||||
|
|
||||||
|
previousConnectionTask = connection.Channel.Output.WriteAsync((byte[])data);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
if (connection.User.Identity.IsAuthenticated)
|
||||||
|
{
|
||||||
|
var userChannel = typeof(THub).FullName + "." + connection.User.Identity.Name;
|
||||||
|
redisSubscriptions.Add(userChannel);
|
||||||
|
|
||||||
|
var previousUserTask = Task.CompletedTask;
|
||||||
|
|
||||||
|
// TODO: Look at optimizing (looping over connections checking for Name)
|
||||||
|
userTask = _bus.SubscribeAsync(userChannel, async (c, data) =>
|
||||||
|
{
|
||||||
|
await previousUserTask;
|
||||||
|
|
||||||
|
previousUserTask = connection.Channel.Output.WriteAsync((byte[])data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.WhenAll(connectionTask, userTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task OnDisconnectedAsync(Connection connection)
|
public override Task OnDisconnectedAsync(Connection connection)
|
||||||
{
|
{
|
||||||
_connections.Remove(connection);
|
_connections.Remove(connection);
|
||||||
|
|
||||||
|
var tasks = new List<Task>();
|
||||||
|
|
||||||
var redisSubscriptions = connection.Metadata.Get<HashSet<string>>("redis_subscriptions");
|
var redisSubscriptions = connection.Metadata.Get<HashSet<string>>("redis_subscriptions");
|
||||||
if (redisSubscriptions != null)
|
if (redisSubscriptions != null)
|
||||||
{
|
{
|
||||||
foreach (var subscription in redisSubscriptions)
|
foreach (var subscription in redisSubscriptions)
|
||||||
{
|
{
|
||||||
await _bus.UnsubscribeAsync(subscription);
|
tasks.Add(_bus.UnsubscribeAsync(subscription));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,9 +172,11 @@ namespace Microsoft.AspNetCore.SignalR.Redis
|
||||||
{
|
{
|
||||||
foreach (var group in groupNames)
|
foreach (var group in groupNames)
|
||||||
{
|
{
|
||||||
await RemoveGroupAsync(connection, group);
|
tasks.Add(RemoveGroupAsync(connection, group));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Task.WhenAll(tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task AddGroupAsync(Connection connection, string groupName)
|
public override async Task AddGroupAsync(Connection connection, string groupName)
|
||||||
|
|
@ -182,14 +199,22 @@ namespace Microsoft.AspNetCore.SignalR.Redis
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await _bus.SubscribeAsync(groupChannel, (c, data) =>
|
var previousTask = Task.CompletedTask;
|
||||||
|
|
||||||
|
await _bus.SubscribeAsync(groupChannel, async (c, data) =>
|
||||||
{
|
{
|
||||||
|
// Since this callback is async, we await the previous task then
|
||||||
|
// before sending the current message. This is because we don't
|
||||||
|
// want to do concurrent writes to the outgoing connections
|
||||||
|
await previousTask;
|
||||||
|
|
||||||
|
var tasks = new List<Task>(group.Connections.Count);
|
||||||
foreach (var groupConnection in group.Connections)
|
foreach (var groupConnection in group.Connections)
|
||||||
{
|
{
|
||||||
// TODO: serialize once per format by providing a different stream?
|
tasks.Add(groupConnection.Channel.Output.WriteAsync((byte[])data));
|
||||||
// TODO: Task Queue
|
|
||||||
groupConnection.Channel.Output.WriteAsync((byte[])data).GetAwaiter().GetResult();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
previousTask = Task.WhenAll(tasks);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue