private async Task BackendDiscoveryHandler()
        {
            while (this.IsRunning)
            {
                try
                {
                    var endpoints = await this.BackendDiscoverer.DiscoverAll();

                    foreach (var endpoint in endpoints)
                    {
                        var endpointId = BitConverter.ToString(endpoint.Encode());

                        var registeredEndpoint = new RegisteredBackend(endpoint, this);

                        if (this.backendEndpoints.TryAdd(endpointId, registeredEndpoint))
                        {
                            registeredEndpoint.Connect();

                            Console.WriteLine($"Backend registered [ {endpointId} ] ");
                            this.backendEndpointIds.Enqueue(endpointId);
                        }
                        else
                        {
                            this.backendEndpoints[endpointId].Heartbeat();
                        }
                    }

                    foreach (var endpointId in this.backendEndpoints.Keys)
                    {
                        if (!endpoints.Any(endpoint => BitConverter.ToString(endpoint.Encode()) == endpointId))
                        {
                            if (this.backendEndpoints.TryRemove(endpointId, out RegisteredBackend expiredBackend))
                            {
                                Console.WriteLine($"Backend {endpointId} expired");
                                expiredBackend.Close();
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message + ": " + ex.StackTrace);
                }

                await Task.Delay(5000);
            }
        }
        private async Task BackendDiscoveryHandler()
        {
            while (this.IsRunning)
            {
                try
                {
                    foreach (var backendDiscoverer in this.BackendDiscoverers)
                    {
                        var backendEndpointIds = this.backendEndpointIds.GetOrAdd(backendDiscoverer.Name, new ConcurrentQueue <string>());

                        var endpoints = await backendDiscoverer.Discoverer.DiscoverAll();

                        foreach (var endpoint in endpoints)
                        {
                            var endpointId = BitConverter.ToString(endpoint.Encode());

                            var registeredEndpoint = new RegisteredBackend(backendDiscoverer.Name, endpoint, this);

                            if (this.backendEndpoints.TryAdd(endpointId, registeredEndpoint))
                            {
                                registeredEndpoint.Connect();

                                this.OnDiagnosticMessage($"Backend registered [ {backendDiscoverer.Name}/{endpointId} ] ");
                                backendEndpointIds.Enqueue(endpointId);
                            }
                            else
                            {
                                this.backendEndpoints[endpointId].Heartbeat();
                            }
                        }

                        foreach (var endpointId in backendEndpointIds)
                        {
                            if (!endpoints.Any(endpoint => BitConverter.ToString(endpoint.Encode()) == endpointId))
                            {
                                if (this.backendEndpoints.TryRemove(endpointId, out RegisteredBackend expiredBackend))
                                {
                                    this.OnDiagnosticMessage($"Backend {backendDiscoverer.Name}/{endpointId} expired");
                                    expiredBackend.Close();

                                    if (this.backendEndpointIds.TryRemove(backendDiscoverer.Name, out var oldEndpoints))
                                    {
                                        this.backendEndpointIds.GetOrAdd(backendDiscoverer.Name, new ConcurrentQueue <string>(oldEndpoints.Where(e => e != endpointId)));
                                    }
                                }
                            }
                        }
                    }

                    foreach (var backendDiscoverer in this.BackendDiscoverers)
                    {
                        this.OnDiagnosticMessage($"Backend: {backendDiscoverer.Name}");

                        var backendEndpointIds = this.backendEndpointIds.GetOrAdd(backendDiscoverer.Name, new ConcurrentQueue <string>());
                        foreach (var eid in backendEndpointIds)
                        {
                            this.OnDiagnosticMessage($"  {eid}");
                        }
                    }
                }
                catch (Exception ex)
                {
                    this.OnDiagnosticMessage(ex.Message + ": " + ex.StackTrace);
                }

                await Task.Delay(5000);
            }
        }
        private async Task Handler()
        {
            while (this.IsRunning)
            {
                try
                {
                    bool isListening      = false;
                    var  connectionString = this.FrontendEndpoint.ToConnectionString();

                    using (var frontendSocket = new RouterSocket())
                        using (this.frontendBuffer = new NetMQQueue <TransportMessage>())
                            using (var poller = new NetMQPoller()
                            {
                                frontendSocket, this.frontendBuffer
                            })
                                using (var monitor = new NetMQ.Monitoring.NetMQMonitor(frontendSocket, $"inproc://monitor.forwarderdevice.{Guid.NewGuid().ToString()}", SocketEvents.Listening | SocketEvents.Accepted | SocketEvents.Disconnected | SocketEvents.Closed))
                                {
                                    frontendSocket.ReceiveReady += (sender, e) =>
                                    {
                                        try
                                        {
                                            var netmqMessage = new NetMQMessage();
                                            while (e.Socket.TryReceiveMultipartMessage(ref netmqMessage))
                                            {
                                                var message = netmqMessage.ToMessage(out var envelope);
                                                //var sourceEnvelope = message.Envelope;

                                                //if (message.Metadata.TryGet("action", out var encodedAction))
                                                //{
                                                //    var action = Encoding.UTF8.GetString(encodedAction);

                                                //    var activity = new Activity(action);
                                                //    if (message.Metadata.TryGet("aid", out var encodedActivityId))
                                                //    {
                                                //        var activityId = Encoding.UTF8.GetString(encodedActivityId);
                                                //        activity.SetParentId(activityId);
                                                //    }

                                                //    message.Metadata.AddOrSet("aid", Encoding.UTF8.GetBytes(activity.Id));
                                                //}

                                                string serviceIdentifier = message.Metadata.TryGetLast("serviceIdentifier", out var encodedService) ? Encoding.UTF8.GetString(encodedService) : null;

                                                this.OnFrontendReceived(message);

                                                var forwardStart = DateTime.UtcNow;
                                                RegisteredBackend registeredBackend = this.ResolveBackend(serviceIdentifier);
                                                if (registeredBackend != null)
                                                {
                                                    message.Metadata.Add($"envelope[{this.Identity}]", envelope);

                                                    registeredBackend.BackendBuffer.Enqueue(message);
                                                }
                                                else
                                                {
                                                    this.OnDiagnosticMessage($"No backends available for {serviceIdentifier}!!!");

                                                    var nmqm = MessageHelpers.CreateNetMQErrorMessage(envelope, "No backends found", message.Metadata);
                                                    e.Socket.SendMultipartMessage(nmqm);
                                                }
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            this.OnDiagnosticMessage(ex.Message + ": " + ex.StackTrace);
                                        }
                                    };

                                    this.frontendBuffer.ReceiveReady += (sender, e) =>
                                    {
                                        try
                                        {
                                            while (this.frontendBuffer.TryDequeue(out TransportMessage message, TimeSpan.Zero))
                                            {
                                                if (!message.Metadata.TryPluckLast($"envelope[{this.Identity}]", out var envelope))
                                                {
                                                    throw new Exception("Message envelope not found");
                                                }

                                                this.OnBackendForwarded(message);

                                                if (!frontendSocket.TrySendMultipartMessage(TimeSpan.FromSeconds(1), message.ToNetMQMessage(envelope)))
                                                {
                                                    this.OnDiagnosticMessage("Failed to forward to frontend");
                                                }
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            this.OnDiagnosticMessage(ex.Message + ": " + ex.StackTrace);
                                        }
                                    };

                                    monitor.Listening += (sender, e) =>
                                    {
                                        this.OnDiagnosticMessage($"Frontend router socket listening at {connectionString}");
                                        isListening = true;
                                    };
                                    monitor.Closed += (sender, e) =>
                                    {
                                        this.OnDiagnosticMessage($"Frontend router socket closed on {connectionString}");
                                        isListening = false;
                                    };
                                    monitor.Accepted += (sender, e) =>
                                    {
                                        this.OnDiagnosticMessage($"Frontend router socket connection accepted at {connectionString}");
                                    };
                                    monitor.Disconnected += (sender, e) =>
                                    {
                                        this.OnDiagnosticMessage($"Frontend router socket disconnected at {connectionString}");
                                    };

                                    this.OnDiagnosticMessage($"Attempting to bind frontend socket to {connectionString}");
                                    monitor.StartAsync();
                                    monitor.AttachToPoller(poller);

                                    var pollerTask = new Task(poller.Run);
                                    pollerTask.ContinueWith((Task task) =>
                                    {
                                        var ex = task.Exception;

                                        this.OnDiagnosticMessage(ex.Message + ": " + ex.StackTrace);
                                        isListening = false;
                                    }, TaskContinuationOptions.OnlyOnFaulted);
                                    pollerTask.Start();

                                    frontendSocket.Bind(connectionString);

                                    var start = DateTime.Now;
                                    while (!isListening)
                                    {
                                        if ((DateTime.Now - start).TotalMilliseconds > 5000)
                                        {
                                            throw new Exception($"Frontend socket bind timeout ({connectionString})");
                                        }

                                        await Task.Delay(1000);
                                    }

                                    while (this.IsRunning && isListening)
                                    {
                                        await Task.Delay(1000);
                                    }

                                    poller.StopAsync();
                                    frontendSocket.Disconnect(connectionString);
                                    monitor.DetachFromPoller();
                                    monitor.Stop();
                                }
                }
                catch (Exception ex)
                {
                    this.OnDiagnosticMessage(ex.Message + ": " + ex.StackTrace);
                }
            }
        }
        private async Task FrontendHandler()
        {
            while (this.IsRunning)
            {
                try
                {
                    bool isListening      = false;
                    var  connectionString = this.FrontendEndpoint.ToConnectionString();

                    using (var frontendSocket = new RouterSocket())
                        using (this.AltFrontendBuffer = new NetMQQueue <TransportMessage>())
                            using (var poller = new NetMQPoller()
                            {
                                frontendSocket, this.AltFrontendBuffer
                            })
                                using (var monitor = new NetMQ.Monitoring.NetMQMonitor(frontendSocket, $"inproc://monitor.routerdevice.frontend.{Guid.NewGuid().ToString()}", SocketEvents.Listening | SocketEvents.Accepted | SocketEvents.Disconnected | SocketEvents.Closed))
                                {
                                    frontendSocket.ReceiveReady += (sender, e) =>
                                    {
                                        try
                                        {
                                            var netmqMessage = new NetMQMessage();
                                            while (e.Socket.TryReceiveMultipartMessage(ref netmqMessage))
                                            {
                                                //Console.WriteLine("Frontend message received");

                                                var message = netmqMessage.ToMessage(out var envelope);

                                                this.OnFrontendReceived(message);

                                                //this.receiveCount++;
                                                //Console.WriteLine("RECEIVED " + this.receiveCount);

                                                //var sourceEnvelope = message.Envelope;

                                                RegisteredBackend registeredBackend = null;
                                                var forwardStart = DateTime.UtcNow;
                                                while (this.IsRunning && registeredBackend == null)
                                                {
                                                    while (this.RegisteredBackendIdentifiers.TryDequeue(out string backendIdentifier))
                                                    {
                                                        registeredBackend = this.RegisteredBackends[backendIdentifier];

                                                        if ((DateTime.UtcNow - registeredBackend.RegsiteredDate).TotalMilliseconds < 2000)
                                                        {
                                                            this.RegisteredBackendIdentifiers.Enqueue(backendIdentifier);
                                                            break;
                                                        }
                                                        else
                                                        {
                                                            if (this.RegisteredBackends.TryRemove(backendIdentifier, out RegisteredBackend expiredBackend))
                                                            {
                                                                Console.WriteLine($"Backend {backendIdentifier} expired");
                                                            }
                                                        }
                                                    }

                                                    if (registeredBackend != null || (DateTime.Now - forwardStart).TotalMilliseconds > 30000)
                                                    {
                                                        break;
                                                    }

                                                    System.Threading.Thread.Sleep(100);
                                                }

                                                if (registeredBackend != null)
                                                {
                                                    //Console.WriteLine($"Forwarding to [ {BitConverter.ToString(registeredBackend.Envelope)} ]");

                                                    message.Metadata.Add($"envelope[{this.Identity}]", envelope);
                                                    message.Metadata.Add($"backendEnvelope[{this.Identity}]", registeredBackend.Envelope);

                                                    this.AltBackendBuffer.Enqueue(message);

                                                    ////this.BackendSocket.SendMultipartMessage(message.ToNetMQMessage(true));
                                                    //if (!this.BackendSocket.TrySendMultipartMessage(TimeSpan.FromSeconds(1), message.ToNetMQMessage(true)))
                                                    //{
                                                    //    Console.WriteLine("Failed to forward to backend");

                                                    //    var forwardedMessage = new Message(1, message.Frames, System.Text.Encoding.UTF8.GetBytes("Failed to forward to backend"), sourceEnvelope);
                                                    //    this.FrontendSocket.SendMultipartMessage(forwardedMessage.ToNetMQMessage(true));
                                                    //}
                                                }
                                                else
                                                {
                                                    Console.WriteLine("No backends available!!!");

                                                    var nmqm = MessageHelpers.CreateNetMQErrorMessage(envelope, "No backends found", message.Metadata);
                                                    e.Socket.SendMultipartMessage(nmqm);
                                                }
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            Console.WriteLine(ex.Message + ": " + ex.StackTrace);
                                        }
                                    };

                                    //var lastFlushed = DateTime.UtcNow;
                                    //frontendSocket.SendReady += (sender, e) =>
                                    //{
                                    //    try
                                    //    {
                                    //        if (!this.BackendBuffer.IsEmpty)
                                    //        {
                                    //            while (this.BackendBuffer.TryDequeue(out Message message))
                                    //            {
                                    //                Console.WriteLine("Backend forwarding");

                                    //                if (!e.Socket.TrySendMultipartMessage(TimeSpan.FromSeconds(1), message.ToNetMQMessage(true)))
                                    //                {
                                    //                    Console.WriteLine("Failed to forward to frontend");

                                    //                    //var forwardedMessage = new Message(1, message.Frames, System.Text.Encoding.UTF8.GetBytes("Failed to forward to backend"), sourceEnvelope);
                                    //                    //this.FrontendSocket.SendMultipartMessage(forwardedMessage.ToNetMQMessage(true));
                                    //                }
                                    //            }

                                    //            lastFlushed = DateTime.UtcNow;
                                    //        }

                                    //        if ((DateTime.UtcNow - lastFlushed).TotalSeconds > 1)
                                    //            Task.Delay(1).Wait();
                                    //    }
                                    //    catch (Exception ex)
                                    //    {
                                    //        Console.WriteLine(ex.Message + ": " + ex.StackTrace);
                                    //    }
                                    //};
                                    this.AltFrontendBuffer.ReceiveReady += (sender, e) =>
                                    {
                                        try
                                        {
                                            while (this.AltFrontendBuffer.TryDequeue(out TransportMessage message, TimeSpan.Zero))
                                            {
                                                if (!message.Metadata.TryPluck($"envelope[{this.Identity}]", out var envelope))
                                                {
                                                    throw new Exception("Message envelope not found");
                                                }

                                                this.OnBackendForwarded(message);

                                                if (!frontendSocket.TrySendMultipartMessage(TimeSpan.FromSeconds(1), message.ToNetMQMessage(envelope)))
                                                {
                                                    Console.WriteLine("Failed to forward to frontend");
                                                }
                                            }
                                        }
                                        catch (Exception ex)
                                        {
                                            Console.WriteLine(ex.Message + ": " + ex.StackTrace);
                                        }
                                    };

                                    monitor.Listening += (sender, e) =>
                                    {
                                        Console.WriteLine($"Frontend router socket listening at {connectionString}");
                                        isListening = true;
                                    };
                                    monitor.Closed += (sender, e) =>
                                    {
                                        Console.WriteLine($"Frontend router socket closed on {connectionString}");
                                        isListening = false;
                                    };
                                    monitor.Accepted += (sender, e) =>
                                    {
                                        Console.WriteLine($"Frontend router socket connection accepted at {connectionString}");
                                    };
                                    monitor.Disconnected += (sender, e) =>
                                    {
                                        Console.WriteLine($"Frontend router socket disconnected at {connectionString}");
                                    };

                                    Console.WriteLine($"Attempting to bind frontend socket to {connectionString}");
                                    monitor.StartAsync();
                                    monitor.AttachToPoller(poller);

                                    var pollerTask = new Task(poller.Run);
                                    pollerTask.ContinueWith((Task task) =>
                                    {
                                        var ex = task.Exception;

                                        Console.WriteLine(ex.Message + ": " + ex.StackTrace);
                                        isListening = false;
                                    }, TaskContinuationOptions.OnlyOnFaulted);
                                    pollerTask.Start();

                                    frontendSocket.Bind(connectionString);

                                    var start = DateTime.Now;
                                    while (!isListening)
                                    {
                                        if ((DateTime.Now - start).TotalMilliseconds > 5000)
                                        {
                                            throw new Exception($"Frontend socket bind timeout ({connectionString})");
                                        }

                                        await Task.Delay(1000);
                                    }

                                    while (this.IsRunning && isListening)
                                    {
                                        if (this.FrontendAnnouncer != null)
                                        {
                                            //Console.WriteLine("Registering frontend");
                                            await this.FrontendAnnouncer.Register(this.FrontendEndpoint);
                                        }

                                        await Task.Delay(1000);
                                    }

                                    poller.StopAsync();
                                    frontendSocket.Disconnect(connectionString);
                                    monitor.DetachFromPoller();
                                    monitor.Stop();
                                }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message + ": " + ex.StackTrace);
                }
            }
        }