Skip to main content

(Part 2) Azure Service Fabric - Parent Child communication and cancellation

Part 1 - http://vunvulearadu.blogspot.ro/2016/03/azure-service-fabric-parent-child.html

Part 2 - http://vunvulearadu.blogspot.ro/2016/03/part-2-azure-service-fabric-parent.html

Solution 1 for the below problem can be found here: http://vunvulearadu.blogspot.ro/2016/03/azure-service-fabric-parent-child.html.

A few weeks ago I so an interesting question on MSDN forum that I think that is pretty common. In this post I will try to give a possible solution to this problem.

Context:
There are multiple instances of the same Restful Stateful Services that are running in parallel. A new instance is created by a 'parent service that also might specifies the action that needs to be executed.
Problem:
The parent service needs to be able to cancel the instance of our Restful Stateless Service based on external factors or based on the current state of the child.


What we need
Basically we need to:

  • Store and map all the service instances that are created by a service
  • Store in a specific location a state related to them
  • Share their state with the parent service
  • Give the ability to the parent to cancel a child service

Solution
The first solution was based on Reliable Collection that allowed us to communicate between parent and child instance. 
The solution is great, but has a big drawback. Parent and child instance type needs to be the same. This means that you will have only a type of service that needs to know to do the logic of the child, but also it has to have the logic used to manage the children's.
  
To be able to split the logic in two different services we would need a mechanism that would allow us to communicate between the instance of our child service and our parent service. 
If we would have Actors ad not Reliable Services, we would use events. Using them we would be able to notify the Parent instances when the instance state would change. Reliable Service doesn't have support for this kind of events.
In this context we need to find a different way to communicate. Of course for cases like this we can go with a classic approach and use:
  • Azure Service Bus Queue - send the change state of a child service to parent
  • Azure Service Bus  Topic - send the change state of a child service to parent
  • Azure Queue - send the change state of a child service to parent
  • Azure Table - store the child state, where child service instance update his state and Parent reads the state when needed
  • Azure Redis Cache or other types of services
Of course we could use any kind of storage or messaging solution to communicate between them. But the problem for all this solution is with the location where we need to make the call. For all of them, we are using an external service that will trigger an external call. Do we really need to use an external storage/messaging solution? 
A solution like this would increase the complexity of our system, maintenance costs, running cost and even it would affect our performance with the latency of our external call.


The real solution
A useful feature of Azure Service Fabric that can be used to resolve our problem is Service Remoting - basically we can call remotely a method of our service. 
In this moment we have two approaches:
  • Expose a method in the child service that would allow parent service us to get the state
  • Expose a method in the parent service that would be called by child service instance each time when the state change
If we would go with the first approach we would need to call all instances of child service at a specific time interval to get the state and if the state was change to update the state mapping or execute a specific action.
We might not be updated soon enough when state change. In the context of long running tasks, we might not need to query the state very often because the state is not changing frequently. The good part of this approach is that the child service doesn't need to have any information about the parent. The parent knows the 'address' of the child and calls him.

The second approach requires from us to expose a method on the parent service that can be called by child service each time when the state change. In this way we will be notified as soon as possible when the the state of a child instance service change.
This is a good approach, but you might have problems if the number of child instances is very high or the state changes very often.

Selected solution
The problem that was described at the beginning of the post was for long running task on child service, where the state is not changing very often.
In this context, I would go and prefer the second solution, where the child services calls the parent each time when the state change.
The downside of this solution is that each child needs to know the address of the parent. This address can be specified in the parameters list in the moment when child is created or a new 'order' is send to him.
The parent service can store and map all the information related to the child services in a reliable collection - Reliable Dictionary might be a good starting point.

Service Remoting Sample
I will write next week how we can do Service Remoting and how does it work. Let's only take a look on how we can call and expose a method of a service that can be called from another service.

Uri statefulServiceUri = new Uri(@"fabric:/Demo.SF/ParentService");
IParentStatefullService parentServiceProxy = 
  ServiceProxy.Create<IParentStatefullService>(1, statefulServiceUri);
parentServiceProxy.StateChange(childId,newState);


In the above example, based on an URI we make a remote call to our parent service. As we can see to make  a basic remote call is very simple. The magic number  1 represents the partition number. In our case we have only one instance of our service in only one partition.

protected override async Task RunAsync(CancellationToken cancelServiceInstance)
{ 
  ...
  
  // State is change, we need to notify our parent.
  Uri statefulServiceUri = new Uri(parentServiceAddress);
  IParentStatefullService parentServiceProxy = 
    ServiceProxy.Create<IParentStatefullService>
      (parentServicePartitionNumber, statefulServiceUri);
  parentServiceProxy.StateChange(childId,newState);
  
  ...
}

Final conclusion
In this post we found two different approaches to establish a communication channel between Parent and Child Services. There is not best solution solution for any use case.
Based on our requirements and constrains we should be able to select the solution that suites our needs.

Part 1 - http://vunvulearadu.blogspot.ro/2016/03/azure-service-fabric-parent-child.html
Part 2 - http://vunvulearadu.blogspot.ro/2016/03/part-2-azure-service-fabric-parent.html

Comments

Post a Comment

Popular posts from this blog

Windows Docker Containers can make WIN32 API calls, use COM and ASP.NET WebForms

After the last post , I received two interesting questions related to Docker and Windows. People were interested if we do Win32 API calls from a Docker container and if there is support for COM. WIN32 Support To test calls to WIN32 API, let’s try to populate SYSTEM_INFO class. [StructLayout(LayoutKind.Sequential)] public struct SYSTEM_INFO { public uint dwOemId; public uint dwPageSize; public uint lpMinimumApplicationAddress; public uint lpMaximumApplicationAddress; public uint dwActiveProcessorMask; public uint dwNumberOfProcessors; public uint dwProcessorType; public uint dwAllocationGranularity; public uint dwProcessorLevel; public uint dwProcessorRevision; } ... [DllImport("kernel32")] static extern void GetSystemInfo(ref SYSTEM_INFO pSI); ... SYSTEM_INFO pSI = new SYSTEM_INFO(...

ADO.NET provider with invariant name 'System.Data.SqlClient' could not be loaded

Today blog post will be started with the following error when running DB tests on the CI machine: threw exception: System.InvalidOperationException: The Entity Framework provider type 'System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer' registered in the application config file for the ADO.NET provider with invariant name 'System.Data.SqlClient' could not be loaded. Make sure that the assembly-qualified name is used and that the assembly is available to the running application. See http://go.microsoft.com/fwlink/?LinkId=260882 for more information. at System.Data.Entity.Infrastructure.DependencyResolution.ProviderServicesFactory.GetInstance(String providerTypeName, String providerInvariantName) This error happened only on the Continuous Integration machine. On the devs machines, everything has fine. The classic problem – on my machine it’s working. The CI has the following configuration: TeamCity .NET 4.51 EF 6.0.2 VS2013 It see...

Navigating Cloud Strategy after Azure Central US Region Outage

 Looking back, July 19, 2024, was challenging for customers using Microsoft Azure or Windows machines. Two major outages affected customers using CrowdStrike Falcon or Microsoft Azure computation resources in the Central US. These two outages affected many people and put many businesses on pause for a few hours or even days. The overlap of these two issues was a nightmare for travellers. In addition to blue screens in the airport terminals, they could not get additional information from the airport website, airline personnel, or the support line because they were affected by the outage in the Central US region or the CrowdStrike outage.   But what happened in reality? A faulty CrowdStrike update affected Windows computers globally, from airports and healthcare to small businesses, affecting over 8.5m computers. Even if the Falson Sensor software defect was identified and a fix deployed shortly after, the recovery took longer. In parallel with CrowdStrike, Microsoft provi...