Search code examples
c#routesowinazure-service-fabricservice-fabric-stateful

URL of Stateful Service using OWIN communication listener


I used the following example to configure a communication listener for my Stateful Service:

https://github.com/Microsoft/azure-docs/blob/master/articles/service-fabric/service-fabric-reliable-services-communication-webapi.md

Relevant snippet:

public Task<string> OpenAsync(CancellationToken cancellationToken)
{
    var serviceEndpoint = this.serviceContext.CodePackageActivationContext.GetEndpoint(this.endpointName);
    var protocol = serviceEndpoint.Protocol;
    int port = serviceEndpoint.Port;

    if (this.serviceContext is StatefulServiceContext)
    {
        StatefulServiceContext statefulServiceContext = this.serviceContext as StatefulServiceContext;

        this.listeningAddress = string.Format(
            CultureInfo.InvariantCulture,
            "{0}://+:{1}/{2}{3}/{4}/{5}",
            protocol,
            port,
            string.IsNullOrWhiteSpace(this.appRoot)
                ? string.Empty
                : this.appRoot.TrimEnd('/') + '/',
            statefulServiceContext.PartitionId,
            statefulServiceContext.ReplicaId,
            Guid.NewGuid());
    }
...

Service manifest snippet:

<Endpoints>
  <Endpoint Protocol="http" Name="ServiceEndpoint" Type="Input" Port="8090" />
  <Endpoint Name="ReplicatorEndpoint" />
</Endpoints>

Now when deploy my application, I get my service on URL with all kind of guids:

http://localhost:8090/ba794109-bba3-4cdf-8434-d718be264087/131407811483781446/614de30b-14a7-4172-a03d-4e28d23cf28d

If I try to access http://localhost:8090/ on itself, I'm getting error 503

Any way to map the general URL to the Primary partition and replica? Or is it impossible in Stateful Services? In Stateless you will get this out of the box.


Solution

  • The "out of the box" solution you are referring to is dependent on the partitioning type. A singleton partition can be accessed by its service URL:

    http://localhost:8090/ApplicationName/ServiceName
    

    This doesn't work for a service with Named or Int64Range partitioning because the URL doesn't refer to a specific partition of the service. That's why you have to call the service URL that contains the GUIDs. The GUIDs refer to the partition.

    In order to solve this problem you could use a reverse proxy. A reverse proxy allows you to provide the partition information through the URL. You can call your partitioned service through the URL:

    http(s)://<Cluster FQDN | internal IP>:Port/<ServiceInstanceName>/<Suffix path>?PartitionKey=<key>&PartitionKind=<partitionkind>&ListenerName=<listenerName>&TargetReplicaSelector=<targetReplicaSelector>&Timeout=<timeout_in_seconds>
    

    In your cluster it would probably look like:

    http://clusterIP:19081/ApplicationName/ServiceName/PartitionKey=1&PartitionKind=Int64Range
    

    Note that the reverse proxy (currently) is not available on the local development cluster. For development purposes I would recommend to either use the URL with GUIDs or temporarely change your partitioning to a singleton scheme.