9
  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?

Darrel Miller
  • 139,164
  • 32
  • 194
  • 243
Raghu
  • 2,859
  • 4
  • 33
  • 65

1 Answers1

26

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.

JohnD
  • 3,884
  • 1
  • 28
  • 40
LoekD
  • 11,402
  • 17
  • 27
  • I have been away for a while. This is awesome. Thank you. – Raghu Aug 08 '16 at 21:42
  • While good, this does not reflect changes due to scaling. (If you run this code, open the explorer (on port 19080) and choose to scale a service to more or less instances, and then run this code again (but don't restart the service that is running), it will return the previous endpoints. – Vaccano Jul 27 '17 at 23:39
  • I believe this (https://github.com/Azure/service-fabric-issues/issues/713) can be connected to what you are stating @Vaccano – marek_lani Mar 23 '18 at 06:56
  • 1
    On the partitions that are 'Singleton', I get an exception for 'FabricServiceNotFoundException: Service does not exist.' with the code above. When I use `fabricClient.ServiceManager.ResolveServicePartitionAsync(service.ServiceName).Result`, the resolved partition is returned successfully. What may be wrong with the use of `resolver.ResolveAsync`? – Stringfellow May 11 '18 at 22:51
  • This is beautiful. – Christian Findlay Apr 03 '19 at 22:58