Skip to content

Commit 9e63685

Browse files
committed
v7.1.1
1 parent f36345a commit 9e63685

File tree

16 files changed

+279
-130
lines changed

16 files changed

+279
-130
lines changed

Directory.Build.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
<RepositoryUrl>https://github.com/managedcode/Orleans.SignalR</RepositoryUrl>
1818
<PackageProjectUrl>https://github.com/managedcode/Orleans.SignalR</PackageProjectUrl>
1919
<Product>Managed Code - Orleans SignalR</Product>
20-
<Version>7.1.0</Version>
21-
<PackageVersion>7.1.0</PackageVersion>
20+
<Version>7.1.1</Version>
21+
<PackageVersion>7.1.1</PackageVersion>
2222

2323
</PropertyGroup>
2424
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">

ManagedCode.Orleans.SignalR.Core/Config/OrleansSignalROptions.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,16 @@ public class OrleansSignalROptions
88
public const string OrleansSignalRStorage = "OrleansSignalRStorage";
99

1010
/// <summary>
11-
/// Gets or sets the time window clients have to send a message before the server closes the connection. The default timeout is 30 seconds.
11+
/// Gets or sets the time window clients have to send a message before the server closes the connection. The default
12+
/// timeout is 30 seconds.
1213
/// </summary>
13-
public TimeSpan? ClientTimeoutInterval { get; set; } = TimeSpan.FromSeconds(30);
14+
public TimeSpan ClientTimeoutInterval { get; set; } = TimeSpan.FromSeconds(30);
15+
16+
/// <summary>
17+
/// If true each connection should be kept alive by sending a message to the orleans every
18+
/// <see cref="HubOptions.KeepAliveInterval" />.
19+
/// The default value is true.
20+
/// Set to false only if you don't want to send messages to the specific connectionId.
21+
/// </summary>
22+
public bool KeepEachConnectionAlive { get; set; } = true;
1423
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System;
2+
using ManagedCode.Orleans.SignalR.Core.Config;
3+
using Microsoft.AspNetCore.SignalR;
4+
using Microsoft.Extensions.Options;
5+
6+
namespace ManagedCode.Orleans.SignalR.Core.Helpers;
7+
8+
public static class TimeIntervalHelper
9+
{
10+
public static TimeSpan GetClientTimeoutInterval(IOptions<OrleansSignalROptions> orleansSignalOptions,
11+
IOptions<HubOptions> hubOptions)
12+
{
13+
var timeSpan = orleansSignalOptions.Value.ClientTimeoutInterval;
14+
15+
if (hubOptions.Value.ClientTimeoutInterval.HasValue && timeSpan > hubOptions.Value.ClientTimeoutInterval)
16+
timeSpan = hubOptions.Value.ClientTimeoutInterval.Value;
17+
18+
return timeSpan;
19+
}
20+
21+
public static TimeSpan GetClientTimeoutInterval(IOptions<OrleansSignalROptions> orleansSignalOptions,
22+
IOptions<HubOptions> globalHubOptions, IOptions<HubOptions> hubOptions)
23+
{
24+
var timeSpan = orleansSignalOptions.Value.ClientTimeoutInterval;
25+
26+
if (globalHubOptions.Value.ClientTimeoutInterval.HasValue &&
27+
timeSpan > globalHubOptions.Value.ClientTimeoutInterval)
28+
timeSpan = globalHubOptions.Value.ClientTimeoutInterval.Value;
29+
30+
if (hubOptions.Value.ClientTimeoutInterval.HasValue && timeSpan > hubOptions.Value.ClientTimeoutInterval)
31+
timeSpan = hubOptions.Value.ClientTimeoutInterval.Value;
32+
33+
return timeSpan;
34+
}
35+
36+
37+
public static TimeSpan GetClientTimeoutInterval(IOptions<HubOptions> globalHubOptions,
38+
IOptions<HubOptions> hubOptions)
39+
{
40+
var timeSpan = TimeSpan.FromSeconds(15);
41+
42+
if (globalHubOptions.Value.ClientTimeoutInterval.HasValue &&
43+
timeSpan > globalHubOptions.Value.ClientTimeoutInterval)
44+
timeSpan = globalHubOptions.Value.ClientTimeoutInterval.Value;
45+
46+
if (hubOptions.Value.ClientTimeoutInterval.HasValue && timeSpan > hubOptions.Value.ClientTimeoutInterval)
47+
timeSpan = hubOptions.Value.ClientTimeoutInterval.Value;
48+
49+
return timeSpan;
50+
}
51+
52+
public static TimeSpan GetKeepAliveInterval(IOptions<HubOptions> globalHubOptions, IOptions<HubOptions> hubOptions)
53+
{
54+
var timeSpan = TimeSpan.FromSeconds(15);
55+
56+
if (globalHubOptions.Value.ClientTimeoutInterval.HasValue)
57+
timeSpan = globalHubOptions.Value.ClientTimeoutInterval.Value;
58+
59+
if (hubOptions.Value.ClientTimeoutInterval.HasValue)
60+
timeSpan = hubOptions.Value.ClientTimeoutInterval.Value;
61+
62+
return timeSpan;
63+
}
64+
}

ManagedCode.Orleans.SignalR.Core/Interfaces/IObserverConnectionManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,5 @@ public interface IObserverConnectionManager
1212
Task RemoveConnection(string connectionId, ISignalRObserver observer);
1313

1414
[OneWay]
15-
ValueTask Ping(ISignalRObserver observer);
15+
Task Ping(ISignalRObserver observer);
1616
}

ManagedCode.Orleans.SignalR.Core/Interfaces/ISignalRInvocationGrain.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ public interface ISignalRInvocationGrain : IGrainWithStringKey, IObserverConnect
1414
Task<ReturnType> TryGetReturnType();
1515

1616
[OneWay]
17-
ValueTask AddInvocation(ISignalRObserver observer, InvocationInfo invocationInfo);
17+
Task AddInvocation(ISignalRObserver observer, InvocationInfo invocationInfo);
1818

1919
[OneWay]
20-
ValueTask<InvocationInfo?> RemoveInvocation();
20+
Task<InvocationInfo?> RemoveInvocation();
2121
}

ManagedCode.Orleans.SignalR.Core/SignalR/Observers/Subscription.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace ManagedCode.Orleans.SignalR.Core.SignalR.Observers;
99
public class Subscription : IDisposable
1010
{
1111
private readonly CancellationTokenSource _cts = new();
12+
private readonly HashSet<IObserverConnectionManager> _grains = new();
1213
private readonly SignalRObserver _observer;
1314
private readonly IDisposable _timer;
1415

@@ -20,14 +21,25 @@ public Subscription(SignalRObserver observer, TimeSpan pingTime)
2021

2122
public ISignalRObserver Reference { get; private set; }
2223

23-
public HashSet<IObserverConnectionManager> Grains { get; } = new();
24+
public IReadOnlyCollection<IObserverConnectionManager> Grains => _grains;
2425

2526
public void Dispose()
2627
{
2728
_cts.Cancel();
2829
_timer.Dispose();
2930
_observer.Dispose();
3031
Reference = null!;
32+
_grains.Clear();
33+
}
34+
35+
public void AddGrain(IObserverConnectionManager grain)
36+
{
37+
_grains.Add(grain);
38+
}
39+
40+
public void RemoveGrain(IObserverConnectionManager grain)
41+
{
42+
_grains.Remove(grain);
3143
}
3244

3345
private void Callback(object? state)
@@ -38,12 +50,15 @@ private void Callback(object? state)
3850
if (token.IsCancellationRequested)
3951
return;
4052

41-
foreach (var grain in Grains)
53+
foreach (var grain in _grains)
4254
{
4355
if (token.IsCancellationRequested)
4456
return;
4557

4658
await grain.Ping(Reference).ConfigureAwait(false);
59+
60+
if (token.IsCancellationRequested)
61+
return;
4762
}
4863
}, _cts.Token).ConfigureAwait(false);
4964
}

ManagedCode.Orleans.SignalR.Core/SignalR/OrleansHubLifetimeManager.cs

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Threading;
88
using System.Threading.Tasks;
99
using ManagedCode.Orleans.SignalR.Core.Config;
10+
using ManagedCode.Orleans.SignalR.Core.Helpers;
1011
using ManagedCode.Orleans.SignalR.Core.Interfaces;
1112
using ManagedCode.Orleans.SignalR.Core.Models;
1213
using ManagedCode.Orleans.SignalR.Core.SignalR.Observers;
@@ -20,40 +21,41 @@ namespace ManagedCode.Orleans.SignalR.Core.SignalR;
2021

2122
public class OrleansHubLifetimeManager<THub> : HubLifetimeManager<THub> where THub : Hub
2223
{
23-
private readonly ILogger _logger;
2424
private readonly IClusterClient _clusterClient;
2525
private readonly HubConnectionStore _connections = new();
26-
private readonly IOptions<HubOptions>? _globalHubOptions;
27-
private readonly IOptions<HubOptions<THub>>? _hubOptions;
28-
private readonly IOptions<OrleansSignalROptions> _options;
26+
private readonly IOptions<HubOptions> _globalHubOptions;
27+
private readonly IOptions<HubOptions<THub>> _hubOptions;
28+
private readonly ILogger _logger;
29+
private readonly IOptions<OrleansSignalROptions> _orleansSignalOptions;
2930

30-
public OrleansHubLifetimeManager(ILogger<OrleansHubLifetimeManager<THub>> logger,
31-
IOptions<OrleansSignalROptions> options, IClusterClient clusterClient, IHubProtocolResolver hubProtocolResolver,
32-
IOptions<HubOptions>? globalHubOptions, IOptions<HubOptions<THub>>? hubOptions)
31+
public OrleansHubLifetimeManager(ILogger<OrleansHubLifetimeManager<THub>> logger, IClusterClient clusterClient,
32+
IHubProtocolResolver hubProtocolResolver, IOptions<OrleansSignalROptions> orleansSignalOptions,
33+
IOptions<HubOptions> globalHubOptions, IOptions<HubOptions<THub>> hubOptions)
3334
{
3435
_logger = logger;
35-
_options = options;
36-
_clusterClient = clusterClient;
36+
_orleansSignalOptions = orleansSignalOptions;
3737
_globalHubOptions = globalHubOptions;
3838
_hubOptions = hubOptions;
39+
_clusterClient = clusterClient;
3940
}
4041

4142
public override async Task OnConnectedAsync(HubConnectionContext connection)
4243
{
43-
var connectionHolderGrain = NameHelperGenerator.GetConnectionHolderGrain<THub>(_clusterClient);
44-
4544
var subscription = CreateConnectionObserver(connection);
4645

47-
//Subscribe the instance to receive messages.
48-
await connectionHolderGrain.AddConnection(connection.ConnectionId, subscription.Reference)
49-
.ConfigureAwait(false);
50-
subscription.Grains.Add(connectionHolderGrain);
46+
if (_orleansSignalOptions.Value.KeepEachConnectionAlive)
47+
{
48+
var connectionHolderGrain = NameHelperGenerator.GetConnectionHolderGrain<THub>(_clusterClient);
49+
await connectionHolderGrain.AddConnection(connection.ConnectionId, subscription.Reference)
50+
.ConfigureAwait(false);
51+
subscription.AddGrain(connectionHolderGrain);
52+
}
5153

5254
if (!string.IsNullOrEmpty(connection.UserIdentifier))
5355
{
5456
var userGrain = NameHelperGenerator.GetSignalRUserGrain<THub>(_clusterClient, connection.UserIdentifier!);
5557
await userGrain.AddConnection(connection.ConnectionId, subscription.Reference).ConfigureAwait(false);
56-
subscription.Grains.Add(userGrain);
58+
subscription.AddGrain(userGrain);
5759
}
5860

5961
_connections.Add(connection);
@@ -162,7 +164,7 @@ public override async Task AddToGroupAsync(string connectionId, string groupName
162164
var groupGrain = NameHelperGenerator.GetSignalRGroupGrain<THub>(_clusterClient, groupName);
163165
await groupGrain.AddConnection(connectionId, subscription.Reference).ConfigureAwait(false);
164166

165-
subscription.Grains.Add(groupGrain);
167+
subscription.AddGrain(groupGrain);
166168
}
167169

168170
public override async Task RemoveFromGroupAsync(string connectionId, string groupName,
@@ -175,7 +177,7 @@ public override async Task RemoveFromGroupAsync(string connectionId, string grou
175177
var groupGrain = NameHelperGenerator.GetSignalRGroupGrain<THub>(_clusterClient, groupName);
176178
await groupGrain.RemoveConnection(connectionId, subscription.Reference).ConfigureAwait(false);
177179

178-
subscription.Grains.Remove(groupGrain);
180+
subscription.RemoveGrain(groupGrain);
179181
}
180182

181183
public override async Task<T> InvokeConnectionAsync<T>(string connectionId, string methodName, object?[] args,
@@ -206,7 +208,7 @@ public override async Task<T> InvokeConnectionAsync<T>(string connectionId, stri
206208
});
207209

208210
var invocationGrain = NameHelperGenerator.GetInvocationGrain<THub>(_clusterClient, invocationId);
209-
subscription.Grains.Add(invocationGrain);
211+
subscription.AddGrain(invocationGrain);
210212
await invocationGrain.AddInvocation(subscription.Reference,
211213
new InvocationInfo(connectionId, invocationId, typeof(T)));
212214

@@ -268,11 +270,20 @@ await NameHelperGenerator.GetInvocationGrain<THub>(_clusterClient, result.Invoca
268270

269271
public override bool TryGetReturnType(string invocationId, [NotNullWhen(true)] out Type? type)
270272
{
271-
var result = NameHelperGenerator.GetInvocationGrain<THub>(_clusterClient, invocationId).TryGetReturnType()
272-
.Result;
273+
var returnType = NameHelperGenerator.GetInvocationGrain<THub>(_clusterClient, invocationId).TryGetReturnType();
274+
275+
var timeSpan =
276+
TimeIntervalHelper.GetClientTimeoutInterval(_orleansSignalOptions, _globalHubOptions, _hubOptions);
277+
Task.WaitAny(returnType, Task.Delay(timeSpan * 0.8));
273278

274-
type = result.GetReturnType();
275-
return result.Result;
279+
if (returnType.IsCompleted)
280+
{
281+
type = returnType.Result.GetReturnType();
282+
return returnType.Result.Result;
283+
}
284+
285+
type = null;
286+
return false;
276287
}
277288

278289
private Subscription CreateConnectionObserver(HubConnectionContext connection)
@@ -282,15 +293,12 @@ private Subscription CreateConnectionObserver(HubConnectionContext connection)
282293
return subscription;
283294
}
284295

296+
285297
private Subscription CreateSubscription(Func<HubMessage, Task>? onNextAction)
286298
{
287-
TimeSpan timeSpan = _globalHubOptions.Value.KeepAliveInterval.Value;
288-
if (timeSpan > _hubOptions.Value.KeepAliveInterval)
289-
{
290-
timeSpan = _hubOptions.Value.KeepAliveInterval.Value;
291-
}
292-
293-
var subscription = new Subscription(new SignalRObserver(onNextAction),timeSpan);
299+
var timeSpan =
300+
TimeIntervalHelper.GetClientTimeoutInterval(_orleansSignalOptions, _globalHubOptions, _hubOptions);
301+
var subscription = new Subscription(new SignalRObserver(onNextAction), timeSpan * 0.8);
294302
var reference = _clusterClient.CreateObjectReference<ISignalRObserver>(subscription.GetObserver());
295303
subscription.SetReference(reference);
296304
return subscription;

ManagedCode.Orleans.SignalR.Server/Extensions/OrleansDependencyInjectionExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public static ISignalRServerBuilder AddOrleans(this ISignalRServerBuilder signal
2424
signalrBuilder.Services.AddOptions<OrleansSignalROptions>().Configure(options);
2525
signalrBuilder.Services.AddSingleton(typeof(HubLifetimeManager<>), typeof(OrleansHubLifetimeManager<>));
2626
signalrBuilder.Services.AddSingleton(typeof(IOrleansHubContext<,>), typeof(OrleansHubContext<,>));
27-
27+
2828
return signalrBuilder;
2929
}
3030
}

0 commit comments

Comments
 (0)