private void ClientOnReceived(ClientController sender, IRecievedMessage message) { var entry = new GatewayEntry { ClientName = sender.Name, Message = message }; foreach (var client in Clients.Where(client => client != sender)) { var messageId = client.Send(message); if (messageId == null) { throw new Exception("Message not sent"); // TODO MKA logging } entry.MessageIds.Add(new KeyValuePair <string, ulong>(client.Name, messageId.Value)); } _entries.Add(entry); }
internal async Task<bool> TryUpdateGatewayEntryAsync(GatewayEntry entry, GossipTableEntry row, string eTag) { row.Status = entry.Status.ToString(); row.GossipTimestamp = entry.HeartbeatTimestamp; return (await TryUpdateTableEntryAsync(row, eTag).ConfigureAwait(false)); }
internal async Task<bool> TryCreateGatewayEntryAsync(GatewayEntry entry) { var row = new GossipTableEntry() { PartitionKey = GlobalServiceId, RowKey = GossipTableEntry.ConstructRowKey(entry.SiloAddress, entry.ClusterId), Status = entry.Status.ToString(), GossipTimestamp = entry.HeartbeatTimestamp }; return (await TryCreateTableEntryAsync(row).ConfigureAwait(false)); }
internal async Task<GossipTableEntry> ReadGatewayEntryAsync(GatewayEntry gateway) { var result = await storage.ReadSingleTableEntryAsync(this.GlobalServiceId, GossipTableEntry.ConstructRowKey(gateway.SiloAddress, gateway.ClusterId)).ConfigureAwait(false); if (result != null) { var tableEntry = result.Item1; try { tableEntry.ParseSiloAddressFromRowKey(); return tableEntry; } catch (Exception exc) { logger.Error( ErrorCode.AzureTable_61, string.Format("Intermediate error parsing GossipTableEntry: {0}. Ignoring this entry.", tableEntry), exc); } } return null; }
public async Task AzureGossip_GatewayGossip() { // start clean await this.gossipTable.DeleteAllEntries(); var ts1 = DateTime.UtcNow; var ts2 = ts1 + new TimeSpan(hours: 0, minutes: 0, seconds: 1); var ts3 = ts1 + new TimeSpan(hours: 0, minutes: 0, seconds: 2); var G1 = new GatewayEntry() { SiloAddress = siloAddress1, ClusterId = "1", HeartbeatTimestamp = ts1, Status = GatewayStatus.Active }; var G2 = new GatewayEntry() { SiloAddress = siloAddress1, ClusterId = "1", HeartbeatTimestamp = ts3, Status = GatewayStatus.Inactive }; var H1 = new GatewayEntry() { SiloAddress = siloAddress2, ClusterId = "2", HeartbeatTimestamp = ts2, Status = GatewayStatus.Active }; var H2 = new GatewayEntry() { SiloAddress = siloAddress2, ClusterId = "2", HeartbeatTimestamp = ts3, Status = GatewayStatus.Inactive }; // push G1 await this.gossipTable.Publish(new MultiClusterData(G1)); // push H1, retrieve G1 var answer = await this.gossipTable.Synchronize(new MultiClusterData(H1)); Assert.Equal(1, answer.Gateways.Count); Assert.True(answer.Gateways.ContainsKey(this.siloAddress1)); Assert.Equal(G1, answer.Gateways[this.siloAddress1]); // push G2, retrieve H1 answer = await this.gossipTable.Synchronize(new MultiClusterData(G2)); Assert.Equal(1, answer.Gateways.Count); Assert.True(answer.Gateways.ContainsKey(this.siloAddress2)); Assert.Equal(H1, answer.Gateways[this.siloAddress2]); // gossip stable await this.gossipTable.Publish(new MultiClusterData(H1)); await this.gossipTable.Publish(new MultiClusterData(G1)); answer = await this.gossipTable.Synchronize(new MultiClusterData(new GatewayEntry[] { H1, G2 })); Assert.True(answer.IsEmpty); // retrieve answer = await this.gossipTable.Synchronize(new MultiClusterData(new GatewayEntry[] { H1, G2 })); Assert.True(answer.IsEmpty); // push H2 await this.gossipTable.Publish(new MultiClusterData(H2)); // retrieve all answer = await this.gossipTable.Synchronize(new MultiClusterData(new GatewayEntry[] { G1, H1 })); Assert.Equal(2, answer.Gateways.Count); Assert.True(answer.Gateways.ContainsKey(this.siloAddress1)); Assert.True(answer.Gateways.ContainsKey(this.siloAddress2)); Assert.Equal(G2, answer.Gateways[this.siloAddress1]); Assert.Equal(H2, answer.Gateways[this.siloAddress2]); }
public async Task AzureGossip_GatewayGossip() { // start clean await gossipTable.DeleteAllEntries(); var ts1 = DateTime.UtcNow; var ts2 = ts1 + new TimeSpan(hours: 0, minutes: 0, seconds: 1); var ts3 = ts1 + new TimeSpan(hours: 0, minutes: 0, seconds: 2); var G1 = new GatewayEntry() { SiloAddress = siloAddress1, ClusterId = "1", HeartbeatTimestamp = ts1, Status = GatewayStatus.Active }; var G2 = new GatewayEntry() { SiloAddress = siloAddress1, ClusterId = "1", HeartbeatTimestamp = ts3, Status = GatewayStatus.Inactive }; var H1 = new GatewayEntry() { SiloAddress = siloAddress2, ClusterId = "2", HeartbeatTimestamp = ts2, Status = GatewayStatus.Active }; var H2 = new GatewayEntry() { SiloAddress = siloAddress2, ClusterId = "2", HeartbeatTimestamp = ts3, Status = GatewayStatus.Inactive }; // push G1 await gossipTable.Publish(new MultiClusterData(G1)); // push H1, retrieve G1 var answer = await gossipTable.Synchronize(new MultiClusterData(H1)); Assert.Equal(1, answer.Gateways.Count); Assert.True(answer.Gateways.ContainsKey(siloAddress1)); Assert.Equal(G1, answer.Gateways[siloAddress1]); // push G2, retrieve H1 answer = await gossipTable.Synchronize(new MultiClusterData(G2)); Assert.Equal(1, answer.Gateways.Count); Assert.True(answer.Gateways.ContainsKey(siloAddress2)); Assert.Equal(H1, answer.Gateways[siloAddress2]); // gossip stable await gossipTable.Publish(new MultiClusterData(H1)); await gossipTable.Publish(new MultiClusterData(G1)); answer = await gossipTable.Synchronize(new MultiClusterData(new GatewayEntry[] { H1, G2 })); Assert.True(answer.IsEmpty); // retrieve answer = await gossipTable.Synchronize(new MultiClusterData(new GatewayEntry[] { H1, G2 })); Assert.True(answer.IsEmpty); // push H2 await gossipTable.Publish(new MultiClusterData(H2)); // retrieve all answer = await gossipTable.Synchronize(new MultiClusterData(new GatewayEntry[] { G1, H1 })); Assert.Equal(2, answer.Gateways.Count); Assert.True(answer.Gateways.ContainsKey(siloAddress1)); Assert.True(answer.Gateways.ContainsKey(siloAddress2)); Assert.Equal(G2, answer.Gateways[siloAddress1]); Assert.Equal(H2, answer.Gateways[siloAddress2]); }
// compare gatewayInfo with gatewayInfoInStorage, and // - write gatewayInfo to storage if it is newer (or do nothing on etag conflict) // - remove expired gateway info from storage // - return gatewayInfoInStorage if it is newer internal async Task<GatewayEntry> DiffAndWriteBackGatewayInfoAsync(GatewayEntry gatewayInfo, GossipTableEntry gatewayInfoInStorage) { if ((gatewayInfo != null && !gatewayInfo.Expired) && (gatewayInfoInStorage == null || gatewayInfoInStorage.GossipTimestamp < gatewayInfo.HeartbeatTimestamp)) { // push the more recent gateway info to storage if (gatewayInfoInStorage == null) { await tableManager.TryCreateGatewayEntryAsync(gatewayInfo); } else { await tableManager.TryUpdateGatewayEntryAsync(gatewayInfo, gatewayInfoInStorage, gatewayInfoInStorage.ETag); } } else if (gatewayInfoInStorage != null && (gatewayInfo == null || gatewayInfo.HeartbeatTimestamp < gatewayInfoInStorage.GossipTimestamp)) { var fromstorage = gatewayInfoInStorage.ToGatewayEntry(); if (fromstorage.Expired) { // remove gateway info from storage await tableManager.TryDeleteGatewayEntryAsync(gatewayInfoInStorage, gatewayInfoInStorage.ETag); } else { // pull the more recent info from storage return fromstorage; } } return null; }
public void MultiClusterData_Gateways() { var ts1 = DateTime.UtcNow; var ts2 = ts1 + new TimeSpan(hours: 0, minutes: 0, seconds: 1); var ts3 = ts1 + new TimeSpan(hours: 0, minutes: 0, seconds: 2); IPAddress ip; Assert.True(IPAddress.TryParse("127.0.0.1", out ip)); IPEndPoint ep1 = new IPEndPoint(ip, 21111); var siloAddress1 = SiloAddress.New(ep1, 0); IPEndPoint ep2 = new IPEndPoint(ip, 21112); var siloAddress2 = SiloAddress.New(ep2, 0); var G1 = new GatewayEntry() { SiloAddress = siloAddress1, ClusterId = "1", HeartbeatTimestamp = ts1, Status = GatewayStatus.Active }; var G2 = new GatewayEntry() { SiloAddress = siloAddress1, ClusterId = "1", HeartbeatTimestamp = ts3, Status = GatewayStatus.Inactive }; var H1 = new GatewayEntry() { SiloAddress = siloAddress2, ClusterId = "2", HeartbeatTimestamp = ts2, Status = GatewayStatus.Active }; var H2 = new GatewayEntry() { SiloAddress = siloAddress2, ClusterId = "2", HeartbeatTimestamp = ts3, Status = GatewayStatus.Inactive }; var gd1 = new MultiClusterData(); var gd2 = new MultiClusterData(G1); var gd3 = new MultiClusterData(G2); TestAlgebraicProperties(gd1, gd1); TestAlgebraicProperties(gd2, gd2); TestAlgebraicProperties(gd1, gd2); TestAlgebraicProperties(gd3, gd1); TestAlgebraicProperties(gd2, gd3); TestAlgebraicProperties(gd3, gd2); gd1 = new MultiClusterData(new GatewayEntry[] { H1, G2 }); gd2 = new MultiClusterData(new GatewayEntry[] { H2, G1 }); TestAlgebraicProperties(gd1, gd1); TestAlgebraicProperties(gd1, gd2); TestAlgebraicProperties(gd2, gd1); gd1 = new MultiClusterData(new GatewayEntry[] { H1, G2 }); gd2 = new MultiClusterData(new GatewayEntry[] { }); TestAlgebraicProperties(gd1, gd2); TestAlgebraicProperties(gd2, gd1); gd1 = new MultiClusterData(new GatewayEntry[] { H1, G2 }); gd2 = new MultiClusterData(new GatewayEntry[] { H1, G1 }); TestAlgebraicProperties(gd1, gd2); TestAlgebraicProperties(gd2, gd1); gd1 = new MultiClusterData(new GatewayEntry[] { H1, G2 }); gd2 = new MultiClusterData(new GatewayEntry[] { G1 }); TestAlgebraicProperties(gd1, gd2); TestAlgebraicProperties(gd2, gd1); gd1 = new MultiClusterData(new GatewayEntry[] { H1, G2 }); gd2 = new MultiClusterData(new GatewayEntry[] { H2 }); TestAlgebraicProperties(gd1, gd2); TestAlgebraicProperties(gd2, gd1); }