4

I've created a stateless service within Service Fabric. It has a SingletonPartition, but multiple instances (InstanceCount is -1 in my case).

I want to communicate with a specific replica of this service. To find all replica's I use:

var fabricClient = new FabricClient();
var serviceUri = new Uri(SERVICENAME);

Partition partition = (await fabricClient.QueryManager.GetPartitionListAsync(serviceUri)).First();
foreach(Replica replica in await fabricClient.QueryManager.GetReplicaListAsync(partition.PartitionInformation.Id))
{
  // communicate with this replica, but how to construct the proxy?
  //var eventHandlerServiceClient = ServiceProxy.Create<IService>(new Uri(replica.ReplicaAddress));
}

The problem is that there is no overload of the ServiceProxy to create one to the replica. Is there another way to communicate with a specific replica?

Edit

The scenario we are building is the following. We have different moving parts with counter information: 1 named partitioned stateful service (with a couple of hundred partitions), 1 int64 partitioned stateful service, and 1 actor with state. To aggregate the counter information, we need to reach out to all service-partitions and actor-instances.

We could of course reverse it and let everyone send there counts to a single (partitioned) service. But that would add a network call in the normal flow (and thus overhead).

Instead, we came up with the following. The mentioned services&actors are combined into one executable and one servicemanifest. Therefore they are in the same process. We add a stateless service with instancecount -1 to the mentioned services&actors. All counter information is stored inside a static variable. The stateless service can read this counter information. Now, we only need to reach out to the stateless service (which has an upper limit of the number of nodes).

Michiel Overeem
  • 3,894
  • 2
  • 27
  • 39

3 Answers3

3

Just to get some terminology out of the way first, "replica" only applies to stateful services where you have a unique replica set for each partition of a service and replicate state between them for HA. Stateless services just have instances, all of which are equal and identical.

Now to answer your actual question: ServiceProxy doesn't have an option to connect to a specific instance of a deployed stateless service. You have the following options:

  • Primary replica: connect to the primary replica of a stateful service partition.
  • Random instance: connect to a random instance of a stateless service.
  • Random replica: connect to a random replica - regardless of its role - of a stateful service partition.
  • Random secondary replica - connect to a random secondary replica of a stateful service partition.

E.g.:

ServiceProxy.Create<IMyService>(serviceUri, partitionKey, TargetReplicaSelector.RandomInstance)

So why no option to connect to a specific stateless service instance?

Well, I would turn this question around and ask why would you want to connect to a specific stateless service instance? By definition, each stateless instance should be identical. If you are keeping some state in there - like user sessions - then now you're stateful and should use stateful services.

You might think of intelligently deciding which instance to connect to for load balancing, but again since it's stateless, no instance should be doing more work than any other as long as requests are distributed evenly. And for that, Service Proxy has the random distribution option.

With that in mind, if you still have some reason to seek out specific stateless service instances, you can always use a different communication stack - like HTTP - and do whatever you want.

Vaclav Turecek
  • 9,020
  • 24
  • 29
  • Ok, The API that returns the instances is called GetReplicaListAsync, that's where the confusing is coming from. We went with your last suggestion: we used HTTP communication. I've edited my question to describe the scenario we are building. – Michiel Overeem Jun 01 '16 at 06:13
  • 1
    @Vaclav Turecek what if I want to expose a WebSockets endpoint in my stateless service? then those instances are not identical since I can have more or fewer connections to each of them. And then I might want to push updates from an actor to the stateless service so the data gets routed to clients over WebSockets – Helikaon Jun 27 '16 at 14:08
  • I suppose I could use Actor events and the stateless web api could subscribe to them – Helikaon Jun 27 '16 at 14:45
  • I can't find any information on the random distribution option for serviceproxy. – jugg1es Mar 03 '17 at 14:50
2

"Well, I would turn this question around and ask why would you want to connect to a specific stateless service instance?"

One example would be if you have multiple (3x) stateless service instances all having WebSocket connections to different clients, let's say 500 each. And you want to notify all 1500 (500x3) users of the same message, if it was possible to connect directly to a specific instance (which I would expect was possible, since I can query for those instances using the FabricClient), I could send a message to each instance which would redirect it to all connected clients.

Instead we have to come up with any of multiple workarounds:

  1. Have all instances connect to some evented system that allows them to trigger on incoming message, e.g. Azure Event Hubs, Azure Service Bus, RedisCache.

  2. Host an additional endpoint, as mentioned here, which makes it 3 endpoints pr service instance: WCF, WebSocket, HTTP.

  3. Change to a stateful partitioned service which doesn't hold any state or any replicas, but simply allows to call partitions.

Currently having some serious issues with RedisCache so migrating away from that, and would like to avoid external dependencies such as Event Hubs and Service Bus just for this scenario.

Sending many messages each second, which will give additional overhead when having to call HTTP, and then the request need to transition over to the WebSocket context.

SondreB
  • 808
  • 7
  • 14
0

In order to target a specific instance of stateless service you can use named partitions. You can have a single instance per partition and use multiple Named partitions. For example, you can have 5 named partitions [0,1,2,3,4] each will have only one instance of the "service". Then you can call it like this

ServiceProxy.Create<IMyService>(serviceUri, partitionKey, TargetReplicaSelector.RandomInstance)

where partitionKey parameter will have one of values [0,1,2,3,4].

the real example would be

_proxyFactory.CreateServiceProxy<IMyService>(
                    _myServiceUri,
                    new ServicePartitionKey("0"), // One of "0,1,2,3,4"
                    TargetReplicaSelector.Default,
                    MyServiceEndpoints.ServiceV1);

This way you can choose one of 5 instances. But all 5 instancies may not be always available. For example during startup or when the service dies and SF is recreating or it is in InBuild stage... So for this reason you should run Partition discovery