Matt Mazzola
Matt Mazzola

Reputation: 5621

Service Fabric Naming Service not forwarding to endpoint assigned to Guest Executable

I have setup an application with two services, one a standard aspnet core api, and another node express app by following the guide here:

https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-deploy-existing-app

When I deploy the application locally I can use the naming service to hit the AspNetCore application such as:

http://localhost:19081/sf_node_test_02/AspNetCore/api/values

Likewise, I expect to be able to hit the api of my guest executable using this address:

http://localhost:19081/sf_node_test_02/NodeApp

However, this does not work. If I use the direct url of the service such as: http://localhost:30032/ I can see the node js app is in fact working as expected.

Now, I know when running the AspNet core application it is explicitly sending it's listening address back to the naming service but the guest executable is not so that explains why they might behave differently. Also, from what I understand the current version of service fabric does not provide the guest executable the information about a dynamically assigned port so it must be hard coded in the service endpoint and also in the application to listen on the same port.

E.g. If I have:

<Endpoint Name="NodeAppTypeEndpoint" Port="30032" Protocol="http" Type="Input" UriScheme="http"/>

Then in the nodejs app I must also have:

const port = process.env.PORT || 30032;
app.listen(port, () => {
    console.log(`Listening on port: ${port}`);
});

Noticed 30032 in both places.

From the documentation:

Furthermore you can ask Service Fabric to publish this endpoint to the Naming Service so other services can discover the endpoint address to this service. This enables you to be able to communicate between services that are guest executables. The published endpoint address is of the form UriScheme://IPAddressOrFQDN:Port/PathSuffix. UriScheme and PathSuffix are optional attributes. IPAddressOrFQDN is the IP address or fully qualified domain name of the node this executable gets placed on, and it is calculated for you.

I interpreted this to mean that if my ServiceManifest.xml has both UseImplicitHost="true" then it should automatically give the naming service the url constructed by the endpoint description.

http://localhost:19081/sf_node_test_02/NodeApp -> http://localhost:30032

Is it correct that service fabric will automatically give the naming service this listening address for this service?

Is there anyway for me to inspect the mapping in the naming service? This would let me know if it does have an entry for my node application but it is just different than what I expect or if in fact it has no entry.

If it doesn't have an entry then I don't know how this guest executable application would be visible to the public when deployed in the cloud either.

Upvotes: 2

Views: 1034

Answers (1)

yoape
yoape

Reputation: 3315

You can use the QueryManager of FabricClient to list registered endpoints for services in your cluster. This should reveal if there is an endpoint for your node service.

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}");
                    }
                }
            }
        }
    }
}

Upvotes: 1

Related Questions