简体   繁体   中英

Service Fabric Web Api to have, both external and Internal endpoints

Some background:

We have a Service Fabric application which contains 2 WebApi services ( and others ). One is our actual front-end API and second one is a proxy to the first one for some specific clients. Both WebApis are exposed to public on different ports. For the communication we used OwinCommunicationListener which comes with the Service template( we just adjusted it to allow using https ). When client call the proxy API, we are currently using HttpClient which is calling public IP address of the actual API.

This obviously doesn't make sense as both WebApis are hosted on the same machines, so instead of going through the internet we would like the communication to be local. For the communication from API to other microservices we used built in ServiceProxy(strongly typed RPC). Currently our front-end API have two listeners (http, https).

To achieve our goal (API to have 2 public http(s) endpoints and one internal) we came up with the idea that we will just add RPC listener to the list of listeners together with http listeners. So in that case the API would have 2 http listeners for public traffic and 1 RPC for internal traffic. In that case we refactored main API to Inherit from

IService

, then we have adjusted CreateServiceInstanceListeners function so it looks like that:

在此处输入图片说明

Now when i run the aplicaiton, the main Web API ( the one which now inherits from IService ) is never getting up - in the diagnostic window i can see infinite loop of creating listeners. Does it mean one cannot use both http listener and internal strongly typed RPC or I am missing something ?

I have read about using Naming Service for service resolution but, i can't find any documentation or example which fits my case.

What i really need to do is to get other's service local address so i can call it locally over http - is it something i can achieve by querying the naming service ? Or maybe i can just use the localhost address?(load is balanced on the front anyway, so i guess it's not required at this point so i can just call the service on the same node)

When creating multiple communication listeners, make sure to name them like this:

protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
        {
            yield return new ServiceInstanceListener(p => new SubscriberCommunicationListener(this, p), "StatelessSubscriberCommunicationListener");
            yield return new ServiceInstanceListener(context => new FabricTransportServiceRemotingListener(context, this), "StatelessFabricTransportServiceRemotingListener");
        }

Here's the code to create a proxy, using the name :

var subStateless = ServiceProxy.Create<ISubscribingStatelessService>(new    
    Uri("fabric:/MyServiceFabricApp/SubscribingStatelessService"),
    listenerName: "StatelessFabricTransportServiceRemotingListener");

Here's a sample implementation.

The Naming Service can be reach through the REST API or by connecting to the cluster through FabricClient . Various operations in those APIs actually use the Naming Service. It is however not a service you could (well, you shouldn't at least) connect to. Instead, you could use the QueryManager of FabricClient to list registered endpoints for services in your cluster. This would show the registered endpoints for your service(s).

var fabricClient = new FabricClient();
var applicationList = fabricClient.QueryManager.GetApplicationListAsync().GetAwaiter().GetResult();
foreach (var application in applicationList)
{
    var serviceList = fabricClient.QueryManager.GetServiceListAsync(application.ApplicationName).GetAwaiter().GetResult();
    foreach (var service in serviceList)
    {
        var partitionListAsync = fabricClient.QueryManager.GetPartitionListAsync(service.ServiceName).GetAwaiter().GetResult();
        foreach (var partition in partitionListAsync)
        {
            var replicas = fabricClient.QueryManager.GetReplicaListAsync(partition.PartitionInformation.Id).GetAwaiter().GetResult();
            foreach (var replica in replicas)
            {
                if (!string.IsNullOrWhiteSpace(replica.ReplicaAddress))
                {
                    var replicaAddress = JObject.Parse(replica.ReplicaAddress);
                    foreach (var endpoint in replicaAddress["Endpoints"])
                    {
                        var endpointAddress = endpoint.First().Value<string>();
                        Console.WriteLine($"{service.ServiceName} {endpointAddress} {endpointAddress}");
                    }
                }
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM