3

I want to migrate typical windows service which is written in .net to Azure using Service fabric.

To implement this , I am creating one service fabric application containing one micro service as guest executable which uses .exe of windows service and deploying application package to service fabric cluster.

After deploying service fabric application on cluster I want windows service should install & start automatically on all nodes however at any time application is running on any single node. I want windows service should run on only one node at a time.

Please kindly help to implement this.

LoekD
  • 11,402
  • 17
  • 27
Amol R
  • 77
  • 1
  • 8
  • You can specify instance count to 1 for your service. Also read this: http://stackoverflow.com/a/39786939/5946937 – LoekD Jan 10 '17 at 13:11

2 Answers2

6

You can certainly run your service as a guest executable. Making sure it only runs on one node can be done by setting the instance count to 1 in the manifest, like so:

  <Parameters>
    <Parameter Name="GuestService_InstanceCount" DefaultValue="-1" />
  </Parameters>
  ...
  <DefaultServices>
    <Service Name="GuestService">
      <StatelessService ServiceTypeName="GuestServiceType" 
                        InstanceCount="[GuestService_InstanceCount]">
        <SingletonPartition />
      </StatelessService>
    </Service>
  </DefaultServices>

Or, you could actually migrate it, not just re-host it in the SF environment...

If your Windows Service is written in .NET and the you wan't to benefit from Service Fabric then the job of migrating the code from a Windows Service to a Reliable Service in Service Fabric should not be to big.

Example for a basic service:

If you start by creating a Stateless Service in a Service Fabric application you end up with a service implementation that looks like (comments removed):

internal sealed class MigratedService : StatelessService
{
    public MigratedService(StatelessServiceContext context)
        : base(context)
    { }

    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
        return new ServiceInstanceListener[0];
    }

    protected override async Task RunAsync(CancellationToken cancellationToken)
    {
        // TODO: Replace the following sample code with your own logic 
        //       or remove this RunAsync override if it's not needed in your service.
        long iterations = 0;
        while (true)
        {
            cancellationToken.ThrowIfCancellationRequested();
            ServiceEventSource.Current.ServiceMessage(this.Context, "Working-{0}", ++iterations);
            await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
        }
    }

The RunAsync method starts running as soon as the Service is up and running on a node in the cluster. It will continue to run until the cluster, for some reason, decides to stop the service, or move it to another node.

In your Windows Service code you should have a method that is run on start. This is usually where you set up a Timer or similar to start doing something on a continuous basis:

protected override void OnStart(string[] args)
{
  System.Timers.Timer timer = new System.Timers.Timer();
  timer.Interval = 60000; // 60 seconds
  timer.Elapsed += new System.Timers.ElapsedEventHandler(this.OnTimer);
  timer.Start();
}

public void OnTimer(object sender, System.Timers.ElapsedEventArgs args)
{
    ...
    DoServiceStuff();
    Console.WriteLine("Windows Service says hello");
}

Now grab that code in OnTimer and put it in your RunAsync method (and any other code you need):

protected override async Task RunAsync(CancellationToken cancellationToken)
{
    while (true)
    {
        cancellationToken.ThrowIfCancellationRequested();
        DoServiceStuff();
        ServiceEventSource.Current.ServiceMessage(this.Context, 
            "Reliable Service says hello");
        await Task.Delay(TimeSpan.FromSeconds(60), cancellationToken);
    }
}

Note the Task.Delay(...), it should be set to the same interval as your Windows Service had for it's Timer.

Now, if you have logging in your Windows Service and you use ETW, then that should work out of the box for you. You simply need to set up some way of looking at those logs from Azure now, for instance using Log Analytics (https://learn.microsoft.com/en-us/azure/log-analytics/log-analytics-service-fabric).

Other things you might have to migrate is if you run specific code on shut down, on continue, and if you have any parameters sent to the service on startup (for instance connection strings to databases). Those need to be converted to configuration settings for the service, look at SO 33928204 for a starting point for that.

Community
  • 1
  • 1
yoape
  • 3,285
  • 1
  • 14
  • 27
  • I'm aware this is a bit old question, but I'm having the same issue with migration. One thing missing is how to migrate code from `on shutdown`. Right now when I stop my service gracefully it first ends it work before closing (I call `RequestAdditionalTime`). Does same thing apply to Fabric? For example, I want my PDF to finish generating before my service stops. – Misiu Oct 25 '18 at 06:30
  • Not really the same for SF. The service will run in a continuous loop until cancelled. The cancellation can be for multiple reasons (SF is changing your replica role, an upgrade of the code, crashing node etc.). The point in the code above where it says cancellationToken.ThrowIfCancellationRequested() is the point where you could try to wrap things up and complete an ongoing workload (PDF generation for instance). – yoape Oct 26 '18 at 07:23
2

The idea behind service fabric is so that it manages your services, from deployment and running. Once you've deployed your service/application to the service fabric instance it will be just like running a windows service (kinda) so you wont need to install your windows service. If you're using something like TopShelf you can just run the exe and everything will run totally fine within service fabric.

Kevin Smith
  • 13,746
  • 4
  • 52
  • 77