diff --git a/specs/ServiceProtocol.md b/specs/ServiceProtocol.md
index be60ea67a..39ecad635 100644
--- a/specs/ServiceProtocol.md
+++ b/specs/ServiceProtocol.md
@@ -5,7 +5,7 @@ The Azure SignalR Service Protocol is a protocol between Azure SignalR Service a
## Terms
- Service - Azure SignalR Service. It accepts connections from both clients and servers, acting as the abstract transport between them. It will internally maintain a one-to-one mapping between clients and servers, to make sure that messages are correctly routed to the recipients as if it is a physical transport.
-- Server - Application server node, which is connected to the Azure SignalR Service, using this protocol to receive data from and send data to clients through Azure SignalR Service.
+- Server - Application server node, which is connected to the Azure SignalR Service, using this protocol to receive data from and send data to clients through Azure SignalR Service.
- Client - The SignalR client connected to the Azure SignalR Service. The Azure SignalR Service will look exactly the same as a self-hosted SignalR server from the client's perspective.
## Overview
@@ -53,7 +53,7 @@ Ack | Service | Sent from Service to Server to return the operation result of Jo
## Communication Model
-This protocol will be used between Service and Server. There will be one or a few physical connections between Service and Server. Data from/to multiple client connections will be multiplexed within these physical connections. Each client connection will be identified by a unique connection Id.
+This protocol will be used between Service and Server. There will be one or a few physical connections between Service and Server. Data from/to multiple client connections will be multiplexed within these physical connections. Each client connection will be identified by a unique connection Id.
The number of client connections will be far more (over 100 times) than the number of physical connections between Service and Server.
@@ -67,15 +67,23 @@ Server will initiate a physical connection to Service, using WebSocket transport
When a new client is connected to Service, a `OpenConnection` message will be sent by Service to Server.
+#### Client migrate-in from another server
+
+When a new client is migrated from another server, a `OpenConnection` message will be sent by Service to Server, with an `Asrs-Migrated-In` header given.
+
### Client Disconnect
- When a client is disconnected from Service, a `CloseConnection` message will be sent by Service to Server.
- When Server wants to disconnect a client, a `CloseConnection` message will be sent by Server to Service. Then Service will disconnect the phyical connection with the target client.
+#### Client migrate-out to another server
+
+When a client is migrated to another server, a `CloseConnection` message will be sent by Service to Server, with an `Asrs-Migrated-Out` header given.
+
### Client Data Pass Through
- When a client sends data to Service, a `ConnectionData` message will be sent by Service to Server.
-- When Server wants to send data to a client, a `ConnectionData` message will be sent by Server to Service.
+- When Server wants to send data to a client, a `ConnectionData` message will be sent by Server to Service.
### SignalR scenarios
@@ -100,6 +108,14 @@ MessagePack uses different formats to encode values. Refer to the [MessagePack F
```
- 1 - Message Type, indicating this is a `HandshakeRequest` message.
- Version - A `Int32` encoding number of the protocol version.
+- ConnectionType - A `Int32` encoding number of the connection type.
+ - 0, Default, it can carry clients, service runtime should always accept this kind of connection.
+ - 1, OnDemand, creating when service requested more connections, it can carry clients, but it may be rejected by service runtime.
+ - 2, Weak, it can not carry clients, but it can send message.
+- MigratableStatus - A `Int32` encoding number indicates if further client connections associated with this server connection could be migrated.
+ - 0, Off, a client connection can not be migrated to another server connection.
+ - 1, Shutdown, message from a client can be sent to any of the server connection within this server. (there is no strong relationship between server/client connection)
+ - 2, Any, message from a client can be sent to any server connection across servers. (the server is stateless)
#### Example: TODO
diff --git a/src/Microsoft.Azure.SignalR.Common/ServiceConnections/ServerConnectionMigrationLevel.cs b/src/Microsoft.Azure.SignalR.Common/ServiceConnections/ServerConnectionMigrationLevel.cs
new file mode 100644
index 000000000..aea2280df
--- /dev/null
+++ b/src/Microsoft.Azure.SignalR.Common/ServiceConnections/ServerConnectionMigrationLevel.cs
@@ -0,0 +1,9 @@
+namespace Microsoft.Azure.SignalR
+{
+ public enum ServerConnectionMigrationLevel
+ {
+ Off = 0,
+ ShutdownOnly = 1,
+ Any = 2,
+ }
+}
diff --git a/src/Microsoft.Azure.SignalR.Protocols/ServiceMessage.cs b/src/Microsoft.Azure.SignalR.Protocols/ServiceMessage.cs
index 7e2a9f6c5..cc652de96 100644
--- a/src/Microsoft.Azure.SignalR.Protocols/ServiceMessage.cs
+++ b/src/Microsoft.Azure.SignalR.Protocols/ServiceMessage.cs
@@ -42,6 +42,18 @@ public class HandshakeRequestMessage : ServiceMessage
///
public int ConnectionType { get; set; }
+ ///
+ /// Gets or sets the migratable flag.
+ ///
+ ///
+ /// 0, Off, a client connection can not be migrated to another server connection.
+ /// 1, ShutdownOnly, a client connection can be migrated only if the pairing server was shutdown gracefully.
+ /// 2, Any, a client connection can be migrated even if the pairing server connection was dropped accidentally. (may cause data loss)
+ ///
+ ///
+ ///
+ public int MigrationLevel { get; set; }
+
///
/// Gets or sets the target of service connection, only work for OnDemand connections.
///
diff --git a/src/Microsoft.Azure.SignalR.Protocols/ServiceProtocol.cs b/src/Microsoft.Azure.SignalR.Protocols/ServiceProtocol.cs
index 287fcc9ef..4b7fe10c0 100644
--- a/src/Microsoft.Azure.SignalR.Protocols/ServiceProtocol.cs
+++ b/src/Microsoft.Azure.SignalR.Protocols/ServiceProtocol.cs
@@ -227,20 +227,12 @@ private static void WriteMessageCore(ServiceMessage message, Stream packer)
private static void WriteHandshakeRequestMessage(HandshakeRequestMessage message, Stream packer)
{
- if (message.ConnectionType == 0)
- {
- MessagePackBinary.WriteArrayHeader(packer, 2);
- MessagePackBinary.WriteInt32(packer, ServiceProtocolConstants.HandshakeRequestType);
- MessagePackBinary.WriteInt32(packer, message.Version);
- }
- else
- {
- MessagePackBinary.WriteArrayHeader(packer, 4);
- MessagePackBinary.WriteInt32(packer, ServiceProtocolConstants.HandshakeRequestType);
- MessagePackBinary.WriteInt32(packer, message.Version);
- MessagePackBinary.WriteInt32(packer, message.ConnectionType);
- MessagePackBinary.WriteString(packer, message.Target ?? string.Empty);
- }
+ MessagePackBinary.WriteArrayHeader(packer, 5);
+ MessagePackBinary.WriteInt32(packer, ServiceProtocolConstants.HandshakeRequestType);
+ MessagePackBinary.WriteInt32(packer, message.Version);
+ MessagePackBinary.WriteInt32(packer, message.ConnectionType);
+ MessagePackBinary.WriteString(packer, message.ConnectionType == 0 ? "" : message.Target ?? string.Empty);
+ MessagePackBinary.WriteInt32(packer, (int) message.MigrationLevel);
}
private static void WriteHandshakeResponseMessage(HandshakeResponseMessage message, Stream packer)
@@ -287,7 +279,7 @@ private static void WriteOpenConnectionMessage(OpenConnectionMessage message, St
private static void WriteCloseConnectionMessage(CloseConnectionMessage message, Stream packer)
{
- MessagePackBinary.WriteArrayHeader(packer, 3);
+ MessagePackBinary.WriteArrayHeader(packer, 4);
MessagePackBinary.WriteInt32(packer, ServiceProtocolConstants.CloseConnectionMessageType);
MessagePackBinary.WriteString(packer, message.ConnectionId);
MessagePackBinary.WriteString(packer, message.ErrorMessage);
@@ -295,7 +287,7 @@ private static void WriteCloseConnectionMessage(CloseConnectionMessage message,
private static void WriteConnectionDataMessage(ConnectionDataMessage message, Stream packer)
{
- MessagePackBinary.WriteArrayHeader(packer, 3);
+ MessagePackBinary.WriteArrayHeader(packer, 4);
MessagePackBinary.WriteInt32(packer, ServiceProtocolConstants.ConnectionDataMessageType);
MessagePackBinary.WriteString(packer, message.ConnectionId);
WriteBinary(packer, message.Payload);
@@ -516,7 +508,8 @@ private static HandshakeRequestMessage CreateHandshakeRequestMessage(byte[] inpu
{
result.ConnectionType = ReadInt32(input, ref offset, "connectionType");
result.Target = ReadString(input, ref offset, "target");
- }
+ }
+ result.MigrationLevel = arrayLength >= 5 ? ReadInt32(input, ref offset, "migratableStatus") : 0;
return result;
}
@@ -553,7 +546,6 @@ private static OpenConnectionMessage CreateOpenConnectionMessage(int arrayLength
{
var headers = ReadHeaders(input, ref offset);
var queryString = ReadString(input, ref offset, "queryString");
-
return new OpenConnectionMessage(connectionId, claims, headers, queryString);
}
else
@@ -575,7 +567,7 @@ private static ConnectionDataMessage CreateConnectionDataMessage(byte[] input, r
var connectionId = ReadString(input, ref offset, "connectionId");
var payload = ReadBytes(input, ref offset, "payload");
- return new ConnectionDataMessage(connectionId, payload);
+ return new ConnectionDataMessage(connectionId, payload);
}
private static MultiConnectionDataMessage CreateMultiConnectionDataMessage(byte[] input, ref int offset)
diff --git a/src/Microsoft.Azure.SignalR.Protocols/ServiceProtocolConstants.cs b/src/Microsoft.Azure.SignalR.Protocols/ServiceProtocolConstants.cs
index 400560bcc..3bc0f2520 100644
--- a/src/Microsoft.Azure.SignalR.Protocols/ServiceProtocolConstants.cs
+++ b/src/Microsoft.Azure.SignalR.Protocols/ServiceProtocolConstants.cs
@@ -25,5 +25,5 @@ public static class ServiceProtocolConstants
public const int JoinGroupWithAckMessageType = 18;
public const int LeaveGroupWithAckMessageType = 19;
public const int AckMessageType = 20;
- }
+ }
}
diff --git a/test/Microsoft.Azure.SignalR.Protocols.Tests/Microsoft.Azure.SignalR.Protocols.Tests.csproj b/test/Microsoft.Azure.SignalR.Protocols.Tests/Microsoft.Azure.SignalR.Protocols.Tests.csproj
index a375191eb..fc6cfb85e 100644
--- a/test/Microsoft.Azure.SignalR.Protocols.Tests/Microsoft.Azure.SignalR.Protocols.Tests.csproj
+++ b/test/Microsoft.Azure.SignalR.Protocols.Tests/Microsoft.Azure.SignalR.Protocols.Tests.csproj
@@ -1,4 +1,4 @@
-
+netcoreapp3.0
diff --git a/test/Microsoft.Azure.SignalR.Protocols.Tests/ServiceProtocolFacts.cs b/test/Microsoft.Azure.SignalR.Protocols.Tests/ServiceProtocolFacts.cs
index 807a5a820..1a98acbc0 100644
--- a/test/Microsoft.Azure.SignalR.Protocols.Tests/ServiceProtocolFacts.cs
+++ b/test/Microsoft.Azure.SignalR.Protocols.Tests/ServiceProtocolFacts.cs
@@ -26,8 +26,17 @@ public static IEnumerable