How can I dynamically discover services hosted in service fabric from API management?
- Lets say that I have service A and B hosted in service fabric cluster. They listen (inside the cluster) on port 7001 and 7002 respectively.
- Lets say that I configure the service fabric load balancer to listen on port 8001 and forward the request to port 7001 (inside the cluster) for service A and listen on port 8002 and forward the request to port 7002 (inside the cluster) for service B.
- Lets say that I configure API management for service A and B and route the requests to appropriate ports on the load balancer.
- This all works.
- Now, instead of manually mapping url route for each service, I would like to dynamically discover services hosted in service fabric (from API management) and route the request at run time dynamically.
- To do this, I know I have to write a policy (in C# most likely) to look up this information from somewhere.
- But I am not sure exactly what to query to lookup load balanced ports and services hosted in service fabric cluster.
- I thought of creating another service C in the same service fabric cluster and use it (from API management) to provide the inside information of the cluster.
- But I was not able to find a way to either look up local service port information or load balanced service port information.
How do I go about it?
Here's a way to discover services and endpoints running in the cluster. (Keep in mind that you'll need to monitor changes too.)
private static void ListEndpoints()
{
var resolver = ServicePartitionResolver.GetDefault();
var fabricClient = new FabricClient();
var apps = fabricClient.QueryManager.GetApplicationListAsync().Result;
foreach (var app in apps)
{
Console.WriteLine($"Discovered application:'{app.ApplicationName}");
var services = fabricClient.QueryManager.GetServiceListAsync(app.ApplicationName).Result;
foreach (var service in services)
{
Console.WriteLine($"Discovered Service:'{service.ServiceName}");
var partitions = fabricClient.QueryManager.GetPartitionListAsync(service.ServiceName).Result;
foreach (var partition in partitions)
{
Console.WriteLine($"Discovered Service Partition:'{partition.PartitionInformation.Kind} {partition.PartitionInformation.Id}");
ServicePartitionKey key;
switch (partition.PartitionInformation.Kind)
{
case ServicePartitionKind.Singleton:
key = ServicePartitionKey.Singleton;
break;
case ServicePartitionKind.Int64Range:
var longKey = (Int64RangePartitionInformation)partition.PartitionInformation;
key = new ServicePartitionKey(longKey.LowKey);
break;
case ServicePartitionKind.Named:
var namedKey = (NamedPartitionInformation)partition.PartitionInformation;
key = new ServicePartitionKey(namedKey.Name);
break;
default:
throw new ArgumentOutOfRangeException("partition.PartitionInformation.Kind");
}
var resolved = resolver.ResolveAsync(service.ServiceName, key, CancellationToken.None).Result;
foreach (var endpoint in resolved.Endpoints)
{
Console.WriteLine($"Discovered Service Endpoint:'{endpoint.Address}");
}
}
}
}
}
You can communicate with the loadbalancer using PowerShell:
Get-AzureRmLoadBalancer
Finally you'll need to come up with a way to match loadbalancer backend ports to service endpoints yourself.