Dajbych.net


Service Fabric Hello World

, 6 minutes to read

service fabric logo

Starting with a console app is simple. Writing a line of text to the console is easy, and the result is visible immediately. A similar situation is with a Universal Windows app where there is a TextBlock control. Service Fabric is not harder. The most difficult part is setting up your diagnostics because cloud services do not have any user interface.

Creating a Project

Launch Visual Studio as an Administrator. Open a New Project dialog (File → New → Project) and choose Service Fabric Application (Installed → Templates → Visual C# → Cloud). Select Stateless Service. The generated project is a hello world application. When you press F5 (or click Start), the Diagnostics Events window will appear and messages logged by the ServiceEventSource.Current.ServiceMessage method in the loop.

Understanding the Entry Point

Just like a console app has its Main method, every instance of a Service Fabric app has its StartAsync method. It is located in the Stateless1.cs file in the Stateless1 project. The method is called automatically after the instance is started in the same way the Main method is called after the console app is launched.

The question is when the method ends. Naturally, it ends when an exception is thrown and is not caught by your code. The console app shuts down, but the Service Fabric instance is restarted without the instance being recreated. In this case, the Service Fabric acts as a watchdog timer. But there is also another indicator signaling when the method should end. It may happen, for example, when the underlying operating system needs to restart after a system update. Two implementations exist. The first one throws an exception:

protected override async Task RunAsync(CancellationToken cancellationToken) {
  while (true) {
    cancellationToken.ThrowIfCancellationRequested();
    ...
  }
}

And the second one ends without reporting a transient fault:

protected override async Task RunAsync(CancellationToken cancellationToken) {
  while (!cancellationToken.IsCancellationRequested) {
    ...
  }
}

Both implementations are correct. The block inside the while loop contains your service logic.

Event Tracing for Windows

ETW is an efficient kernel-level tracing mechanism. You can consume the events in real time or from a log file. It does not slow down the application because it drops events when logging to a file if the disk is too slow to keep up with the logging rate.

Every event source has its name. It is defined in the EventSourceAttribute decorating the ServiceEventSource class in the ServiceEventSource.cs file. The Stateless1 class is registered with this class to ETW in the Program.cs file by calling the ServiceTypeRegistered method.

Service Fabric Analytics

OMS (Operations Manager Suite) allows your organization to centralize monitoring of various services regardless of their kind. It can also be used to monitor your Service Fabric cluster if you set up Azure Diagnostics on your Service Fabric VMs and configure OMS to collect data from your WAD (Windows Azure Diagnostics) storage table.

Application Insights

Another option is taking advantage of AI (Application Insights). The configuration was a little bit easier in the past by applying a single package, but this approach is deprecated now (most probably because it was bypassing ETW).

In order to connect AI to the ETW source, we have to include two projects from GitHub. Projects are not available as NuGet packages. You can keep always up-to-date by cloning the source repository, but this approach is very disruptive because you usually need the latest stable, well-tested version rather than the latest bits.

There is another choice. You can install the Microsoft.Diagnostics.EventFlow.ServiceFabric NuGet package. It has many dependencies and does not support .NET Core in this scenario. After installing the package, your project is richer by one file only, which is very positive. The file path is PackageRoot\Config\eventFlowConfig.json. In this file, you need to uncomment the section with Application Insights settings and paste the instrumentation key.

{
  "outputs": [
    {
      "type": "ApplicationInsights",
      "instrumentationKey": "00000000-0000-0000-0000-000000000000"
    }
  ]
}

Next, we need to identify the source of events, which is the value of the Name property in EventSourceAttribute decorating the ServiceEventSource class in the ServiceEventSource.cs file.

{
  "inputs": [
    {
      "type": "EventSource",
      "sources": [
        { "providerName": "MyCompany-StatelessService-Stateless1" }
      ]
    }
  ]
}

Finally, you have to replace the default entry point of the service host process with the diagnostic pipeline.

private static void Main() {
    try {
        using (var diagnosticsPipeline = ServiceFabricDiagnosticPipelineFactory.CreatePipeline("MyApplication-MyService-DiagnosticsPipeline")) {
            ServiceRuntime.RegisterServiceAsync("Stateless1Type", ctx => new Stateless1(ctx)).Wait();

            ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(Stateless1).Name);

            Thread.Sleep(Timeout.Infinite);
        }
    } catch (Exception e) {
        ServiceEventSource.Current.ServiceHostInitializationFailed(e.ToString());
        throw;
    }
}

Unfortunately, even running this approach locally ends up with exceptions of various kinds depending on the target framework (.NET 4.5.2, .NET 4.6.2) and NuGet dependency behavior (lowest, highest).

My workaround

Install the Microsoft.ApplicationInsights.WindowsServer NuGet package.

Create an instance of the TelemetryClient class in a singleton or a static class.

using Microsoft.ApplicationInsights;
internal sealed class Stateless1 : StatelessService {
    private readonly TelemetryClient telemetry = new TelemetryClient();
    ...
}

Modify the ApplicationInsights.config file by inserting the instrumentation key into it.

<?xml version="1.0" encoding="utf-8"?>
<ApplicationInsights xmlns="http://schemas.microsoft.com/ApplicationInsights/2013/Settings">
  <InstrumentationKey>00000000-0000-0000-0000-000000000000</InstrumentationKey>
  ...
</ApplicationInsights>

Use the TelemetryClient as a gateway to your Application Insights telemetry.

protected override async Task RunAsync(CancellationToken cancellationToken) {
    long iterations = 0;
    while (true) {
        cancellationToken.ThrowIfCancellationRequested();
        telemetry.TrackTrace($"Hello World - {iterations}");
        await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
    }
}

Deploying to a Service Fabric Cluster

The first step is to create a Service Fabric Cluster. I recommend creating a separate Resource group for it, because alongside the cluster, many other resources will be created – several storage accounts, a virtual machine scale set, a virtual network, a load balancer, and a public IP address. Future deletion of the Service Fabric cluster with all its dependencies will be much easier.

Service Fabric can be found in the Azure portal under NewComputeService Fabric Cluster.

For testing purposes, I recommend the following configuration:

When the cluster is created, select Publish… from the context menu of the Service Fabric Application project. Select the endpoint ending with cloudapp.azure.com:19000 and click Publish.

In the Azure Portal, on the Service Fabric panel, click on…

…and make sure your application is healthy.

In the Azure Portal, on the Application Insights panel, click on…

…and then click on the little +

…write a single word…

…and click on…

…then you can see your diagnostic messages from your cluster.

When you are done, you can delete your application from the cluster in the Service Fabric Explorer. To do so, select the application in the left panel and choose the Delete Application command under the Actions button in the upper right corner.