Alex Gordon
Alex Gordon

Reputation: 60741

FabricException: The primary or stateless instance for the partition

I am following a tutorial from [this book]: enter image description here

I am getting the following exception: enter image description here

There's no doubt that my nodes are running fine:enter image description here

Here's how my stateless service is setup:

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

        /// <summary>
        /// Optional override to create listeners (e.g., TCP, HTTP) for this service replica to handle client or user requests.
        /// </summary>
        /// <returns>A collection of listeners.</returns>
        protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
        {
            return new ServiceInstanceListener[0];
        }


        /// <summary>
        /// This is the main entry point for your service instance.
        /// </summary>
        /// <param name="cancellationToken">Canceled when Service Fabric needs to shut down this service instance.</param>
        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 way I deploy and get this exception:enter image description here

What am I doing wrong? How can I get my client connected to my cluster?

The entire solution can be viewed here.

Upvotes: 2

Views: 681

Answers (3)

Francesco Bonizzi
Francesco Bonizzi

Reputation: 5302

Two things:

  1. Your ICalculatorService have to be defined in another library project, in order to be shared between your stateless service library and your client project. So:

    • Create a new library project MyStatelessService.Interfaces
    • Add to it NuGet package: Microsoft.ServiceFabric.Services.Remoting
    • Define in this library your ICalculatorService
    • Remove ICalculatorService from your other two projects
    • Add a reference to MyStatelessService.Interfaces to your client application and your stateless service library.
    • Fix references to ICalculatorService
    • All your ICalculatorService should be referenced from the same library

Your client will be:

using Microsoft.ServiceFabric.Services.Remoting.Client;
using MyStatelessService.Interfaces;
using System;

static void Main(string[] args)
{
    var calculatorClient = ServiceProxy.Create<ICalculatorService>
        (new Uri("fabric:/CalculatorService/MyStatelessService"));

    var result = calculatorClient.Add(1, 2).Result;

    Console.WriteLine(result);
    Console.ReadKey();
}
  1. Change your MyStatelessService's Program.cs part after the try statement with this:

    ServiceRuntime.RegisterServiceAsync("MyStatelessServiceType",
        context => new CalculatorService(context)).GetAwaiter().GetResult();
    
    ServiceEventSource.Current.ServiceTypeRegistered(Process.GetCurrentProcess().Id, typeof(CalculatorService).Name);
    

Instead of CalculatorService, you were referencing MyStatelessService.

Upvotes: 2

Wouter B
Wouter B

Reputation: 731

When creating your stateless service you called your service MyStatelessService instead of CalculatorService and you called your application CalculatorService instead of CalculatorApplication. As the book states at step 1 under 'The first version' "Create a new Service Fabric application named CalculatorApplication with a service named CalculatorService". You created an application named CalculatorService and a service called MyStatelessService. You then made a new service file within the stateless service project. You should never create a new service within a service. Use the generated service.cs (MyStatelessService.cs in your case) file instead. One way to solve your problem is to copy the implementation of CalculatorService into your stateless service and delete CalculatorService.cs. Your stateless service will be:

internal sealed class MyStatelessService: StatelessService, ICalculatorService
{
    public MyStatelessService(StatelessServiceContext serviceContext) : base(serviceContext)
    {

    }

    public Task<int> Add(int a, int b)
    {
        return Task.FromResult<int>(a + b);
    }

    public Task<int> Subtract(int a, int b)
    {
        return Task.FromResult<int>(a - b);
    }

    protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
    {
        return new[] { new ServiceInstanceListener(context => this.CreateServiceRemotingListener(context)) };
    }
}

However, it's unconventional to call an application 'service', so I'd recommend to create a new project and paste your current implementation into it.

When creating a new project, name your application CalculatorApplication. Adding the application

And then create the service with the name CalculatorService. Adding the service

Your CalculatorService.cs file is made automatically, so just paste your current implementation into it. (The same as MyStatelessService above, but with the name CalculatorService.)

Upvotes: 0

LoekD
LoekD

Reputation: 11470

You're attempting to access your service through remoting, but your service is not enabled for remoting.

You need to return a communication listener from CreateServiceInstanceListeners and implement IService.

Upvotes: 2

Related Questions