Search code examples
c#azureazure-service-fabricstateful

Error while creating and installing TCP Stateful Service Fabric


I'm trying to build a tcp/ip server based on a Azure Service Fabric's StatefulService. The problem is when running locally. Visual Studio failed to install the service with the following error:

fabric:/TCPTestServerFabric/TCPTestService is not ready, 1 partitions remaining.

And Service Fabric Explorer:

Partition is below target replica or instance count.
fabric:/TCPTestServerFabric/TCPTestService 1 1 61eee22a-c5d4-46e8-ab57-8d41009abc3d
  N/P InBuild _Node_0 133444395888851522

For more information see: <a href='https://aka.ms/sfhealth' target='_blank'>https://aka.ms/sfhealth</a>

BUT... installed it anyway and debugging it like there is no problem at all. From a TCP client app, I some how able to connect to the server with ip and port number and sent message to the server and got response back. I've tried to remove the code in the OpenAsync method in the TCPTestService and this doesn't helped either. The errors above still occurred.

I checked my diskspace and is not a problem, I have about 250 gb free space. Also played with one these options in the Service Fabric properties and doesn't helped either.

enter image description here

Anyone idea what did I do wrong? Thank's in advance.

    internal sealed class TCPTestService : StatefulService
    {
        public TCPTestService(StatefulServiceContext context) : base(context) { }

        protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
        {
            return new[] { new ServiceReplicaListener(context => 
                           new TCPTestServer(context, StateManager), "ServiceEndpoint") };
        }

        protected override async Task RunAsync(CancellationToken cancellationToken)
        {
            //cancellationToken.WaitHandle.WaitOne();
        }
    }
    public class TCPTestServer : ICommunicationListener
    {
        private readonly StatefulServiceContext _context;
        private readonly IReliableStateManager _stateManager;

        public TCPTestServer(StatefulServiceContext context, IReliableStateManager stateManager) 
        {
            _context = context;
            _stateManager = stateManager;
        }

        public void Abort()
        {
            ServiceEventSource.Current.ServiceMessage(_context, $"Request aborted");
        }

        public Task CloseAsync(CancellationToken cancellationToken)
        {
            ServiceEventSource.Current.ServiceMessage(_context, $"Server closed");
            return Task.FromCanceled(cancellationToken);
        }

        public async Task<string> OpenAsync(CancellationToken cancellationToken)
        {
            while (true)
            {
                cancellationToken.ThrowIfCancellationRequested();

                try
                {
                    EndpointResourceDescription serviceEndpoint = _context.CodePackageActivationContext.GetEndpoint("ServiceEndpoint");
                    int port = serviceEndpoint.Port;

                    IPEndPoint ipEndPoint = new( IPAddress.Parse( "127.0.0.1" ), port);
                    using Socket listener = new(
                        ipEndPoint.AddressFamily,
                        SocketType.Stream,
                        ProtocolType.Tcp);

                    listener.Bind(ipEndPoint);
                    listener.Listen();
                    ServiceEventSource.Current.ServiceMessage(_context, $"Server started");

                    Socket handler = await listener.AcceptAsync();
                    ServiceEventSource.Current.ServiceMessage(_context, $"Incoming connection: {handler.AddressFamily}");

                    while (true)
                    {
                        //cancellationToken.ThrowIfCancellationRequested();

                        // Receive message.
                        var buffer = new byte[1_024];
                        var received = await handler.ReceiveAsync(buffer, SocketFlags.None);
                        var response = Encoding.UTF8.GetString(buffer, 0, received);

                        if (!string.IsNullOrWhiteSpace(response))
                        {
                            ServiceEventSource.Current.ServiceMessage(_context, $"Incoming message: {response}");

                            var ackMessage = "<ACK/>";
                            var echoBytes = Encoding.UTF8.GetBytes(ackMessage);
                            int bytesSent = await handler.SendAsync(echoBytes, 0);

                            ServiceEventSource.Current.ServiceMessage(_context, $"Sent message: {ackMessage}");
                        }
                        else
                        {
                            ServiceEventSource.Current.ServiceMessage(_context, $"Disconnected");
                            break; //Disconnected
                        }
                    }
                }
                catch (Exception ex)
                {
                    ServiceEventSource.Current.ServiceMessage(_context, $"Error: {ex.Message}");
                }
            }
        }
    }

Solution

  • Just answering my own question, in case you might need it someday. Get rid of ICommunicationListener implementation and copy the content of OpenAsync method to the Stateful service implementation. Also you need to check listener whether or not it's created already.