private static string CalculateNameForService(SF_Partition partition, int listenerIndex) { StringBuilder serviceName = new StringBuilder(partition.serviceName_.PathAndQuery.Substring(1).Replace('/', '_')); if (partition.listeners_[listenerIndex].Name != "") { serviceName.Append("_"); serviceName.Append(partition.listeners_[listenerIndex].Name); } serviceName.Append("|*|-2"); return(serviceName.ToString()); }
private static void AddPartitionToService(Guid partitionId, SF_Partition partitionInfo) { for (int listenerIndex = 0; listenerIndex < partitionInfo.listeners_.Count; listenerIndex++) { string serviceName = CalculateNameForService(partitionInfo, listenerIndex); if (!services_.ContainsKey(serviceName)) { services_[serviceName] = new ServicePartitions { EndpointIndex = listenerIndex, StatefulService = (partitionInfo.serviceKind_ == ServiceKind.Stateful), Partitions = new List <Guid>() }; } var entry = services_[serviceName].Partitions.Find(x => x == partitionId); if (entry == Guid.Empty) { services_[serviceName].Partitions.Add(partitionId); } } }
private static void AddPartitionToService(Guid partitionId, SF_Partition partitionInfo) { EnvoyDefaults.LogMessage(String.Format("Added: {0}={1}", partitionId, JsonConvert.SerializeObject(partitionInfo))); for (int listenerIndex = 0; listenerIndex < partitionInfo.listeners_.Count; listenerIndex++) { string serviceName = CalculateNameForService(partitionInfo, listenerIndex); if (!services_.ContainsKey(serviceName)) { services_[serviceName] = new ServicePartitions { EndpointIndex = listenerIndex, StatefulService = (partitionInfo.serviceKind_ == ServiceKind.Stateful), Partitions = new List <Guid>() }; } var entry = services_[serviceName].Partitions.Find(x => x == partitionId); if (entry == Guid.Empty) { services_[serviceName].Partitions.Add(partitionId); } } }
/// <summary> /// This function gathers the state of the cluster on startup and caches the information /// Changes to cluster state are handled through notifications. /// /// Capture information for each replica for every service running in the cluster. /// </summary> /// <returns></returns> public static async Task InitializePartitionData() { EnvoyDefaults.LogMessage("InitializePartitionData started"); // Populate data locally Dictionary <Guid, SF_Partition> partitionData = new Dictionary <Guid, SF_Partition>(); var queryManager = client.QueryManager; ApplicationList applications = null; try { applications = await queryManager.GetApplicationListAsync(); } catch (Exception e) { EnvoyDefaults.LogMessage("GetApplicationListAsync failed"); EnvoyDefaults.LogMessage(String.Format("Error={0}", e.Message)); EnvoyDefaults.LogMessage(String.Format("Error={0}", e.StackTrace)); Environment.FailFast("GetApplicationListAsync failed"); } EnvoyDefaults.LogMessage("GetApplicationListAsync Succeeded"); foreach (var application in applications) { var services = await queryManager.GetServiceListAsync(application.ApplicationName); foreach (var service in services) { var partitions = await queryManager.GetPartitionListAsync(service.ServiceName); foreach (var partition in partitions) { List <SF_Endpoint> listeners = new List <SF_Endpoint>(); var replicas = await queryManager.GetReplicaListAsync(partition.PartitionInformation.Id); foreach (var replica in replicas) { if (replica.ReplicaAddress.Length == 0) { continue; } JObject addresses; try { addresses = JObject.Parse(replica.ReplicaAddress); } catch { continue; } var replicaListeners = addresses["Endpoints"].Value <JObject>(); foreach (var replicaListener in replicaListeners) { var role = ServiceEndpointRole.Stateless; if (partition.ServiceKind == ServiceKind.Stateful) { var statefulRole = ((StatefulServiceReplica)replica).ReplicaRole; switch (statefulRole) { case ReplicaRole.Primary: role = ServiceEndpointRole.StatefulPrimary; break; case ReplicaRole.ActiveSecondary: role = ServiceEndpointRole.StatefulSecondary; break; default: role = ServiceEndpointRole.Invalid; break; } } int listenerIndex = listeners.FindIndex(x => x.Name == replicaListener.Key); if (listenerIndex == -1) { listeners.Add(new SF_Endpoint(replicaListener.Key)); listenerIndex = listeners.Count - 1; } try { var listenerAddressString = replicaListener.Value.ToString(); if (!listenerAddressString.StartsWith("http") && !listenerAddressString.StartsWith("https")) { continue; } var listenerAddress = new Uri(replicaListener.Value.ToString()); if (listenerAddress.HostNameType == UriHostNameType.Dns) { var ipaddrs = Dns.GetHostAddresses(listenerAddress.Host); foreach (var ipaddr in ipaddrs) { if (ipaddr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) { var saddrstring = ipaddr.ToString(); if (saddrstring.StartsWith("172")) { listenerAddress = new Uri(listenerAddress.Scheme + "://" + saddrstring + ":" + listenerAddress.Port + listenerAddress.PathAndQuery); break; } } } } listeners[listenerIndex].AddInstance(role, listenerAddress); } catch (System.Exception e) { EnvoyDefaults.LogMessage(String.Format("Error={0}", e)); } } } // Remove any listeners without active endpoints listeners.RemoveAll(x => x.InstanceCount() == 0); if (listeners.Count == 0) { continue; } var partitionInfo = new SF_Partition(service.ServiceName, service.ServiceKind, partition.PartitionInformation, null, listeners); partitionData[partition.PartitionInformation.Id] = partitionInfo; } } } // Process changes received through notifications lock (lock_) { foreach (var partition in partitionsAdd_) { partitionData[partition.Key] = partition.Value; } foreach (var partition in partitionsRemove_) { partitionData.Remove(partition.Key); } // Finally update global state, populate Service List and log details partitions_ = partitionData; services_ = new Dictionary <string, ServicePartitions>(); foreach (var partition in partitionData) { AddPartitionToService(partition.Key, partition.Value); EnvoyDefaults.LogMessage(String.Format("Added: {0}={1}", partition.Key, JsonConvert.SerializeObject(partition.Value))); } partitionsRemove_ = null; partitionsAdd_ = null; } }
private static void Handler(Object sender, EventArgs eargs) { try { var notification = ((FabricClient.ServiceManagementClient.ServiceNotificationEventArgs)eargs).Notification; if (notification.Endpoints.Count == 0) { //remove lock (lock_) { if (partitions_ != null) { partitions_.Remove(notification.PartitionId); RemovePartitionFromService(notification.PartitionId); } else { partitionsAdd_.Remove(notification.PartitionId); partitionsRemove_[notification.PartitionId] = null; } EnvoyDefaults.LogMessage(String.Format("Removed: {0}", notification.PartitionId)); return; } } List <SF_Endpoint> listeners = new List <SF_Endpoint>(); ServiceEndpointRole role = ServiceEndpointRole.Invalid; foreach (var notificationEndpoint in notification.Endpoints) { if (notificationEndpoint.Address.Length == 0) { continue; } JObject addresses; try { addresses = JObject.Parse(notificationEndpoint.Address); } catch { continue; } var notificationListeners = addresses["Endpoints"].Value <JObject>(); foreach (var notificationListener in notificationListeners) { int listenerIndex = listeners.FindIndex(x => x.Name == notificationListener.Key); if (listenerIndex == -1) { listeners.Add(new SF_Endpoint(notificationListener.Key)); listenerIndex = listeners.Count - 1; } try { var listenerAddressString = notificationListener.Value.ToString(); if (!listenerAddressString.StartsWith("http") && !listenerAddressString.StartsWith("https")) { continue; } var listenerAddress = new Uri(listenerAddressString); if (listenerAddress.HostNameType == UriHostNameType.Dns) { var ipaddrs = Dns.GetHostAddresses(listenerAddress.Host); foreach (var ipaddr in ipaddrs) { if (ipaddr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) { var saddrstring = ipaddr.ToString(); if (saddrstring.StartsWith("172")) { listenerAddress = new Uri(listenerAddress.Scheme + "://" + saddrstring + ":" + listenerAddress.Port + listenerAddress.PathAndQuery); break; } } } } listeners[listenerIndex].AddInstance(notificationEndpoint.Role, listenerAddress); } catch (System.Exception e) { EnvoyDefaults.LogMessage(String.Format("Error={0}", e)); } } if (role == ServiceEndpointRole.Invalid) { role = notificationEndpoint.Role; } } // Remove any listeners without active endpoints listeners.RemoveAll(x => x.InstanceCount() == 0); if (listeners.Count == 0) { return; } var partitionInfo = new SF_Partition(notification.ServiceName, (role == ServiceEndpointRole.Stateless) ? ServiceKind.Stateless : ServiceKind.Stateful, notification.PartitionInfo, notification.Version, listeners ); lock (lock_) { if (partitions_ != null) { partitions_[notification.PartitionId] = partitionInfo; AddPartitionToService(notification.PartitionId, partitionInfo); } else { partitionsRemove_.Remove(notification.PartitionId); partitionsAdd_[notification.PartitionId] = partitionInfo; } EnvoyDefaults.LogMessage(String.Format("Added: {0}={1}", notification.PartitionId, JsonConvert.SerializeObject(partitionInfo))); } } catch (Exception e) { EnvoyDefaults.LogMessage(String.Format("Error={0}", e.Message)); EnvoyDefaults.LogMessage(String.Format("Error={0}", e.StackTrace)); } }