How can I dynamically discover services hosted in service fabric from API management?

  1. 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.
  2. 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.
  3. Lets say that I configure API management for service A and B and route the requests to appropriate ports on the load balancer.
  4. This all works.
  5. 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.
  6. To do this, I know I have to write a policy (in C# most likely) to look up this information from somewhere.
  7. But I am not sure exactly what to query to lookup load balanced ports and services hosted in service fabric cluster.
  8. 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.
  9. 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.