Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 1.6.1 #1117

Merged
merged 19 commits into from
Nov 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
298 changes: 234 additions & 64 deletions docs/diagnostic-logs.md

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/diagnostic-logs/message-path.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
40 changes: 40 additions & 0 deletions docs/sharding.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ In latest SDK, we add support for configuring multiple SignalR service instances
* [How to add multiple endpoints from code](#aspnet-code)
* [How to customize endpoint router](#aspnet-customize-router)
* [Configuration in cross-geo scenarios](#cross-geo)
* [Dynamic Scale ServiceEndpoints](#dynamic-scale)
* [Failover](#failover)

## For ASP.NET Core
Expand Down Expand Up @@ -112,6 +113,19 @@ private class CustomRouter : EndpointRouterDecorator
}
```

From version 1.6.0, we're exposing metrics synced from service side to help with customized routing for balancing and load use. So you can select the endpoints with minimal clients in below sample.

```cs
private class CustomRouter : EndpointRouterDecorator
{
public override ServiceEndpoint GetNegotiateEndpoint(HttpContext context, IEnumerable<ServiceEndpoint> endpoints)
{
return endpoints.OrderBy(x => x.EndpointMetrics.ClientConnectionCount).FirstOrDefault(x => x.Online) // Get the available endpoint with minimal clients load
?? base.GetNegotiateEndpoint(context, endpoints); // Or fallback to the default behavior to randomly select one from primary endpoints, or fallback to secondary when no primary ones are online
}
}
```

And don't forget to register the router to DI container using:

```cs
Expand Down Expand Up @@ -202,6 +216,20 @@ private class CustomRouter : EndpointRouterDecorator
}
}
```

Another example about you can select the endpoints with minimal clients, supported from version 1.6.0.

```cs
private class CustomRouter : EndpointRouterDecorator
{
public override ServiceEndpoint GetNegotiateEndpoint(HttpContext context, IEnumerable<ServiceEndpoint> endpoints)
{
return endpoints.OrderBy(x => x.EndpointMetrics.ClientConnectionCount).FirstOrDefault(x => x.Online) // Get the available endpoint with minimal clients load
?? base.GetNegotiateEndpoint(context, endpoints); // Or fallback to the default behavior to randomly select one from primary endpoints, or fallback to secondary when no primary ones are online
}
}
```

And don't forget to register the router to DI container using:

```cs
Expand Down Expand Up @@ -235,6 +263,18 @@ In cross-geo scenario, when a client `/negotiate` with the app server hosted in

![Normal Negotiate](./images/normal_negotiate.png)

## Dynamic Scale ServiceEndpoints
<a name="dynamic-scale"></a>

From version 1.5.0, we're enabling dynamic scale ServiceEndpoints for ASP.NET Core version first. So you don't have to restart app server when you need to add/remove a ServiceEndpoint. As ASP.NET Core is supporting default configuration like `appsettings.json` with `reloadOnChange: true`, you don't need to change a code and it's supported by nature. And if you'd like to add some customized configuration and work with hot-reload, please refer to [this](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1).

> Note
>
> Considering the time of connection set-up between server/service and client/service may be a few difference, to ensure no message loss during the scale process, we have a staging period waiting for server connection be ready before open the new ServiceEndpoint to clients. Usually it takes seconds to complete and you'll be able to see log like `Succeed in adding endpoint: '{endpoint}'` which indicates the process completes. But for some unexpected reasons like cross-region network issue or configuration inconsistent on different app servers, the staging period will not be able to finish correctly. Since limited things can be done during the dynamic scale process, we choose to promote the scale as it is. It's suggested to restart App Server when you find the scaling process not working correctly.
>
> The default timeout period for the scale is 5 minutes, and it can be customized by setting the value in [`ServiceOptions.ServiceScaleTimeout`](https://github.com/Azure/azure-signalr/blob/dev/docs/use-signalr-service.md#servicescaletimeout). If you have a lot of app servers, it's suggested to extend the value a little more.


## Failover
<a name="failover"></a>

Expand Down
336 changes: 1 addition & 335 deletions docs/tsg.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/use-signalr-service.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ services.AddSignalR()
options.AccessTokenLifetime = TimeSpan.FromDays(1);
options.ClaimsProvider = context => context.User.Claims;

option.GracefulShutdown.Mode = GracefulShutdownMode.WaitForClientsClose;
option.GracefulShutdown.Timeout = TimeSpan.FromSeconds(10);
options.GracefulShutdown.Mode = GracefulShutdownMode.WaitForClientsClose;
options.GracefulShutdown.Timeout = TimeSpan.FromSeconds(10);
});
```

Expand Down
8 changes: 7 additions & 1 deletion samples/ChatSample/ChatSample/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Azure.SignalR;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
Expand All @@ -18,7 +19,12 @@ public void ConfigureServices(IServiceCollection services)
.AddAzureSignalR(option =>
{
option.GracefulShutdown.Mode = GracefulShutdownMode.WaitForClientsClose;
option.GracefulShutdown.Timeout = TimeSpan.FromSeconds(10);
option.GracefulShutdown.Timeout = TimeSpan.FromSeconds(30);

option.GracefulShutdown.Add<Chat>(async (c) =>
{
await c.Clients.All.SendAsync("exit");
});
})
.AddMessagePackProtocol();
}
Expand Down
22 changes: 20 additions & 2 deletions samples/ChatSample/ChatSample/wwwroot/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,17 @@ <h2 class="text-center" style="margin-top: 0; padding-top: 30px; padding-bottom:
<div class="modal-content">
<div class="modal-header">
<div>Connection Error...</div>
<div><strong style="font-size: 1.5em;">Hit Refresh/F5</strong> to rejoin. ;)</div>
<div><strong style="font-size: 1.5em;">Hit Refresh/F5</strong> to rejoin. :)</div>
</div>
</div>
</div>
</div>
<div class="modal alert alert-success fade" id="closeModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<div>Connection Closed</div>
<div><strong style="font-size: 1.5em;">Hit Refresh/F5</strong> to rejoin. :)</div>
</div>
</div>
</div>
Expand Down Expand Up @@ -97,9 +107,15 @@ <h2 class="text-center" style="margin-top: 0; padding-top: 30px; padding-bottom:
messageBox.appendChild(messageEntry);
messageBox.scrollTop = messageBox.scrollHeight;
};

var close = function (name, message) {
setTimeout(() => connection.stop(), 3000);
}

// Create a function that the hub can call to broadcast messages.
connection.on('broadcastMessage', messageCallback);
connection.on('echo', messageCallback);
connection.on('exit', close);
connection.onclose(onConnectionError);
}

Expand Down Expand Up @@ -138,8 +154,10 @@ <h2 class="text-center" style="margin-top: 0; padding-top: 30px; padding-bottom:
function onConnectionError(error) {
if (error && error.message) {
console.error(error.message);
var modal = document.getElementById('myModal');
} else {
var modal = document.getElementById('closeModal');
}
var modal = document.getElementById('myModal');
modal.classList.add('in');
modal.style = 'display: block;';
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Azure.SignalR.Protocol;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ public Uri BuildAuthority()
return GetUri(AzureActiveDirectoryInstance, TenantId);
}

public async Task<string> AcquireAccessToken()
public override async Task<string> AcquireAccessToken()
{
var result = await AzureActiveDirectoryHelper.BuildApplication(this).AcquireTokenForClient(DefaultScopes).WithSendX5C(true).ExecuteAsync();
var app = AzureActiveDirectoryHelper.BuildApplication(this);
var result = await app.AcquireTokenForClient(DefaultScopes).WithSendX5C(true).ExecuteAsync();
return result.AccessToken;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class AadManagedIdentityOptions : AuthOptions, IAadTokenGenerator
{
internal override string AuthType => "ManagedIdentity";

public async Task<string> AcquireAccessToken()
public override async Task<string> AcquireAccessToken()
{
var azureServiceTokenProvider = new AzureServiceTokenProvider(azureAdInstance: AzureActiveDirectoryInstance);
return await azureServiceTokenProvider.GetAccessTokenAsync(Audience);
Expand Down
7 changes: 5 additions & 2 deletions src/Microsoft.Azure.SignalR.Common/Auth/AuthOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Threading.Tasks;

namespace Microsoft.Azure.SignalR
{
Expand All @@ -19,8 +20,12 @@ public abstract class AuthOptions

internal const string USGovernmentInstance = "https://login.microsoftonline.us/";

internal abstract string AuthType { get; }

protected string AzureActiveDirectoryInstance { get; set; } = GlobalInstance;

public abstract Task<string> AcquireAccessToken();

public AuthOptions WithChina()
{
AzureActiveDirectoryInstance = ChinaInstance;
Expand Down Expand Up @@ -57,7 +62,5 @@ internal Uri BuildMetadataAddress()
}

protected Uri GetUri(string baseUri, string path) => new Uri(new Uri(baseUri), path);

internal abstract string AuthType { get; }
}
}
8 changes: 7 additions & 1 deletion src/Microsoft.Azure.SignalR.Common/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ internal static class Constants
{
public static class Keys
{
public const string AzureSignalRSectionKey = "Azure:SignalR";
public const string ServerStickyModeDefaultKey = "Azure:SignalR:ServerStickyMode";
public const string ConnectionStringDefaultKey = "Azure:SignalR:ConnectionString";
public const string ApplicationNameDefaultKey = "Azure:SignalR:ApplicationName";
Expand Down Expand Up @@ -40,6 +41,10 @@ public static class Periods
public static readonly TimeSpan DefaultServersPingInterval = TimeSpan.FromSeconds(5);
// Depends on DefaultStatusPingInterval, make 1/2 to fast check.
public static readonly TimeSpan DefaultCloseDelayInterval = TimeSpan.FromSeconds(5);

// Custom handshake timeout of SignalR Service
public const int DefaultHandshakeTimeout = 15;
public const int MaxCustomHandshakeTimeout = 30;
}

public static class ClaimType
Expand All @@ -58,6 +63,7 @@ public static class ClaimType
public const string ServiceEndpointsCount = AzureSignalRSysPrefix + "secn";
public const string MaxPollInterval = AzureSignalRSysPrefix + "ttl";
public const string DiagnosticClient = AzureSignalRSysPrefix + "dc";
public const string CustomHandshakeTimeout = AzureSignalRSysPrefix + "cht";

public const string AzureSignalRUserPrefix = "asrs.u.";
}
Expand Down Expand Up @@ -85,4 +91,4 @@ public static class Protocol
public const string BlazorPack = "blazorpack";
}
}
}
}
Loading