Deploy and remove applications using FabricClient


Once an application type has been packaged, it's ready for deployment into an Azure Service Fabric cluster. Deployment involves the following three steps:

  1. Upload the application package to the image store
  2. Register the application type
  3. Remove the application package from the image store
  4. Create the application instance

After you deploy an application and run an instance in the cluster, you can delete the application instance and its application type. Completely remove an application from the cluster by following these steps:

  1. Remove (or delete) the running application instance
  2. Unregister the application type if you no longer need it

If you use Visual Studio for deploying and debugging applications on your local development cluster, all the preceding steps are handled automatically through a PowerShell script. This script is found in the Scripts folder of the application project. This article provides background on what that script is doing so that you can do the same operations outside of Visual Studio.

Connect to the cluster

Connect to the cluster by creating a FabricClient instance before you run any of the code examples in this article. For examples of connecting to a local development cluster or a remote cluster or cluster secured using Microsoft Entra ID, X509 certificates, or Windows Active Directory see Connect to a secure cluster. To connect to the local development cluster, run the following example:

// Connect to the local cluster.
FabricClient fabricClient = new FabricClient();

Upload the application package

Suppose you build and package an application named MyApplication in Visual Studio. By default, the application type name listed in the ApplicationManifest.xml is "MyApplicationType". The application package, which contains the necessary application manifest, service manifests, and code/config/data packages, is located in C:\Users<username>\Documents\Visual Studio 2019\Projects\MyApplication\MyApplication\pkg\Debug.

Uploading the application package puts it in a location that's accessible by the internal Service Fabric components. Service Fabric verifies the application package during the registration of the application package. However, if you want to verify the application package locally (that is, before uploading), use the Test-ServiceFabricApplicationPackage cmdlet.

The CopyApplicationPackage API uploads the application package to the cluster image store.

If the application package is large and/or has many files, you can compress it and copy it to the image store using PowerShell. The compression reduces the size and the number of files.

See Understand the image store connection string for supplementary information about the image store and image store connection string.

Register the application package

The application type and version declared in the application manifest become available for use when the application package is registered. The system reads the package uploaded in the previous step, verifies the package, processes the package contents, and copies the processed package to an internal system location.

The ProvisionApplicationAsync API registers the application type in the cluster and make it available for deployment.

The GetApplicationTypeListAsync API provides information about all successfully registered application types. You can use this API to determine when the registration is done.

Remove an application package from the image store

It's recommended that you remove the application package after the application is successfully registered. Deleting application packages from the image store frees up system resources. Keeping unused application packages consumes disk storage and leads to application performance issues. Delete the application package from the image store using the RemoveApplicationPackage API.

Create an application instance

You can instantiate an application from any application type that has been registered successfully by using the CreateApplicationAsync API. The name of each application must start with the "fabric:" scheme and must be unique for each application instance (within a cluster). Any default services defined in the application manifest of the target application type are also created.

Multiple application instances can be created for any given version of a registered application type. Each application instance runs in isolation, with its own working directory and set of processes.

To see which named applications and services are running in the cluster, run the GetApplicationListAsync and GetServiceListAsync APIs.

Create a service instance

You can instantiate a service from a service type using the CreateServiceAsync API. If the service is declared as a default service in the application manifest, the service is instantiated when the application is instantiated. Calling the CreateServiceAsync API for a service that is already instantiated will return an exception of type FabricException. The exception will contain an error code with a value of FabricErrorCode.ServiceAlreadyExists.

Remove a service instance

When a service instance is no longer needed, you can remove it from the running application instance by calling the DeleteServiceAsync API.

Warning

This operation cannot be reversed, and service state cannot be recovered.

Remove an application instance

When an application instance is no longer needed, you can permanently remove it by name using the DeleteApplicationAsync API. DeleteApplicationAsync automatically removes all services that belong to the application as well, permanently removing all service state.

Warning

This operation cannot be reversed, and application state cannot be recovered.

Unregister an application type

When a particular version of an application type is no longer needed, you should unregister that particular version of the application type using the Unregister-ServiceFabricApplicationType API. Unregistering unused versions of application types releases storage space used by the image store. A version of an application type can be unregistered as long as no applications are instantiated against that version of the application type. Also, the application type can have no pending application upgrades are referencing that version of the application type.

Troubleshooting

Copy-ServiceFabricApplicationPackage asks for an ImageStoreConnectionString

The Service Fabric SDK environment should already have the correct defaults set up. But if needed, the ImageStoreConnectionString for all commands should match the value that the Service Fabric cluster is using. You can find the ImageStoreConnectionString in the cluster manifest, retrieved using the Get-ServiceFabricClusterManifest and Get-ImageStoreConnectionStringFromClusterManifest commands:

PS C:\> Get-ImageStoreConnectionStringFromClusterManifest(Get-ServiceFabricClusterManifest)

The Get-ImageStoreConnectionStringFromClusterManifest cmdlet, which is part of the Service Fabric SDK PowerShell module, is used to get the image store connection string. To import the SDK module, run:

Import-Module "$ENV:ProgramFiles\Microsoft SDKs\Service Fabric\Tools\PSModule\ServiceFabricSDK\ServiceFabricSDK.psm1"

The ImageStoreConnectionString is found in the cluster manifest:

<ClusterManifest xmlns:xsd="https://www.w3.org/2001/XMLSchema" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" Name="Server-Default-SingleNode" Version="1.0" xmlns="http://schemas.microsoft.com/2011/01/fabric">

    [...]

    <Section Name="Management">
      <Parameter Name="ImageStoreConnectionString" Value="file:D:\ServiceFabric\Data\ImageStore" />
    </Section>

    [...]

See Understand the image store connection string for supplementary information about the image store and image store connection string.

Deploy large application package

Issue: CopyApplicationPackage API times out for a large application package (order of GB). Try:

  • Specify a larger timeout for CopyApplicationPackage method, with timeout parameter. By default, the timeout is 30 minutes.
  • Check the network connection between your source machine and cluster. If the connection is slow, consider using a machine with a better network connection. If the client machine is in another region than the cluster, consider using a client machine in a closer or same region as the cluster.
  • Check if you are hitting external throttling. For example, when the image store is configured to use azure storage, upload may be throttled.

Issue: Upload package completed successfully, but ProvisionApplicationAsync API times out. Try:

  • Compress the package before copying to the image store. The compression reduces the size and the number of files, which in turn reduces the amount of traffic and work that Service Fabric must perform. The upload operation may be slower (especially if you include the compression time), but register and unregister the application type are faster.
  • Specify a larger timeout for ProvisionApplicationAsync API with timeout parameter.

Deploy application package with many files

Issue: ProvisionApplicationAsync times out for an application package with many files (order of thousands). Try:

Code example

The following example copies an application package to the image store and provisions the application type. Then, the example creates an application instance and creates a service instance. Finally, the example removes the application instance, unprovisions the application type, and deletes the application package from the image store.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Threading.Tasks;

using System.Fabric;
using System.Fabric.Description;
using System.Threading;

namespace ServiceFabricAppLifecycle
{
class Program
{
static void Main(string[] args)
{

    string clusterConnection = "localhost:19000";
    string appName = "fabric:/MyApplication";
    string appType = "MyApplicationType";
    string appVersion = "1.0.0";
    string serviceName = "fabric:/MyApplication/Stateless1";
    string imageStoreConnectionString = "file:C:\\SfDevCluster\\Data\\ImageStoreShare";
    string packagePathInImageStore = "MyApplication";
    string packagePath = "C:\\Users\\username\\Documents\\Visual Studio 2019\\Projects\\MyApplication\\MyApplication\\pkg\\Debug";
    string serviceType = "Stateless1Type";

    // Connect to the cluster.
    FabricClient fabricClient = new FabricClient(clusterConnection);

    // Copy the application package to a location in the image store
    try
    {
        fabricClient.ApplicationManager.CopyApplicationPackage(imageStoreConnectionString, packagePath, packagePathInImageStore);
        Console.WriteLine("Application package copied to {0}", packagePathInImageStore);
    }
    catch (AggregateException ae)
    {
        Console.WriteLine("Application package copy to Image Store failed: ");
        foreach (Exception ex in ae.InnerExceptions)
        {
            Console.WriteLine("HResult: {0} Message: {1}", ex.HResult, ex.Message);
        }
    }

    // Provision the application.  "MyApplicationV1" is the folder in the image store where the application package is located. 
    // The application type with name "MyApplicationType" and version "1.0.0" (both are found in the application manifest) 
    // is now registered in the cluster.            
    try
    {
        fabricClient.ApplicationManager.ProvisionApplicationAsync(packagePathInImageStore).Wait();

        Console.WriteLine("Provisioned application type {0}", packagePathInImageStore);
    }
    catch (AggregateException ae)
    {
        Console.WriteLine("Provision Application Type failed:");

        foreach (Exception ex in ae.InnerExceptions)
        {
            Console.WriteLine("HResult: {0} Message: {1}", ex.HResult, ex.Message);
        }
    }

    // Delete the application package from a location in the image store.
    try
    {
        fabricClient.ApplicationManager.RemoveApplicationPackage(imageStoreConnectionString, packagePathInImageStore);
        Console.WriteLine("Application package removed from {0}", packagePathInImageStore);
    }
    catch (AggregateException ae)
    {
        Console.WriteLine("Application package removal from Image Store failed: ");
        foreach (Exception ex in ae.InnerExceptions)
        {
            Console.WriteLine("HResult: {0} Message: {1}", ex.HResult, ex.Message);
        }
    }

    //  Create the application instance.
    try
    {
        ApplicationDescription appDesc = new ApplicationDescription(new Uri(appName), appType, appVersion);
        fabricClient.ApplicationManager.CreateApplicationAsync(appDesc).Wait();
        Console.WriteLine("Created application instance of type {0}, version {1}", appType, appVersion);
    }
    catch (AggregateException ae)
    {
        Console.WriteLine("CreateApplication failed.");
        foreach (Exception ex in ae.InnerExceptions)
        {
            Console.WriteLine("HResult: {0} Message: {1}", ex.HResult, ex.Message);
        }
    }

    // Create the stateless service description.  For stateful services, use a StatefulServiceDescription object.
    StatelessServiceDescription serviceDescription = new StatelessServiceDescription();
    serviceDescription.ApplicationName = new Uri(appName);
    serviceDescription.InstanceCount = 1;
    serviceDescription.PartitionSchemeDescription = new SingletonPartitionSchemeDescription();
    serviceDescription.ServiceName = new Uri(serviceName);
    serviceDescription.ServiceTypeName = serviceType;

    // Create the service instance.  If the service is declared as a default service in the ApplicationManifest.xml,
    // the service instance is already running and this call will fail.
    try
    {
        fabricClient.ServiceManager.CreateServiceAsync(serviceDescription).Wait();
        Console.WriteLine("Created service instance {0}", serviceName);
    }
    catch (AggregateException ae)
    {
        Console.WriteLine("CreateService failed.");
        foreach (Exception ex in ae.InnerExceptions)
        {
            Console.WriteLine("HResult: {0} Message: {1}", ex.HResult, ex.Message);
        }
    }

    // Delete a service instance.
    try
    {
        DeleteServiceDescription deleteServiceDescription = new DeleteServiceDescription(new Uri(serviceName));

        fabricClient.ServiceManager.DeleteServiceAsync(deleteServiceDescription);
        Console.WriteLine("Deleted service instance {0}", serviceName);
    }
    catch (AggregateException ae)
    {
        Console.WriteLine("DeleteService failed.");
        foreach (Exception ex in ae.InnerExceptions)
        {
            Console.WriteLine("HResult: {0} Message: {1}", ex.HResult, ex.Message);
        }
    }

    // Delete an application instance from the application type.
    try
    {
        DeleteApplicationDescription deleteApplicationDescription = new DeleteApplicationDescription(new Uri(appName));

        fabricClient.ApplicationManager.DeleteApplicationAsync(deleteApplicationDescription).Wait();
        Console.WriteLine("Deleted application instance {0}", appName);
    }
    catch (AggregateException ae)
    {
        Console.WriteLine("DeleteApplication failed.");
        foreach (Exception ex in ae.InnerExceptions)
        {
            Console.WriteLine("HResult: {0} Message: {1}", ex.HResult, ex.Message);
        }
    }

    // Un-provision the application type.
    try
    {
        fabricClient.ApplicationManager.UnprovisionApplicationAsync(appType, appVersion).Wait();
        Console.WriteLine("Un-provisioned application type {0}, version {1}", appType, appVersion);
    }
    catch (AggregateException ae)
    {
        Console.WriteLine("Un-provision application type failed: ");
        foreach (Exception ex in ae.InnerExceptions)
        {
            Console.WriteLine("HResult: {0} Message: {1}", ex.HResult, ex.Message);
        }
    }

    Console.WriteLine("Hit enter...");
    Console.Read();
}        
}
}

Next steps

Service Fabric application upgrade

Service Fabric health introduction

Diagnose and troubleshoot a Service Fabric service

Model an application in Service Fabric