Inheritance: IDisposable
 public void Sync_can_create_many_clients_with_pool() {
     var payloadstring = "";
     using(ServerBuilder.CreateSync(new IPEndPoint(IPAddress.Parse("127.0.0.1"), _port))
         .WithCommand("BIN")
         .HandledBy(request => {
             var payload = new StringBuilder();
             for(var i = 0; i < 10; i++) {
                 payload.Append(Guid.NewGuid().ToString());
             }
             payloadstring = payload.ToString();
             return Response.Create("OK").WithData(Encoding.ASCII.GetBytes(payloadstring));
         })
         .Register()
         .Build()
     ) {
         Console.WriteLine("created server");
         var pool = ConnectionPool.Create("127.0.0.1", _port);
         var n = 20000;
         var t = Stopwatch.StartNew();
         for(var i = 0; i < n; i++) {
             using(var client = new ClacksClient(pool)) {
                 var response = client.Exec(new Client.Request("BIN").ExpectData("OK"));
                 Assert.AreEqual("OK", response.Status);
                 Assert.AreEqual(1, response.Arguments.Length);
                 Assert.AreEqual(payloadstring, Encoding.ASCII.GetString(response.Data));
             }
         }
         t.Stop();
         var rate = n / t.Elapsed.TotalSeconds;
         Console.WriteLine("Executed {0} connect/commmands at {1:0}commands/second", n, rate);
     }
 }
 public void Single_Response_Handler_is_called_exactly_once_per_request() {
     var requestCount = 0;
     using(ServerBuilder.CreateSync(new IPEndPoint(IPAddress.Parse("127.0.0.1"), _port))
         .WithCommand("PING")
             .ExpectsNoData()
                 .HandledBy(request => {
                     requestCount++;
                     return Response.Create("PONG");
                 })
             .Register()
         .Build()
         ) {
         _log.Debug("created server");
         using(var client = new ClacksClient("127.0.0.1", _port)) {
             _log.Debug("created client");
             client.Exec(new Client.Request("PING"));
             _log.Debug("got response");
             Assert.AreEqual(1, requestCount);
         }
     }
 }
 private void DisconnectTest(ClacksServer server) {
     _log.Debug("creating server");
     using(server) {
         _log.Debug("created server");
         using(var client = new ClacksClient("127.0.0.1", _port)) {
             Assert.IsFalse(client.Disposed);
             Console.WriteLine("created client");
             var response = client.Exec(new Client.Request("BYE"));
             _log.Debug("got response");
             Assert.AreEqual("BYE", response.Status);
             _log.Debug("checking disposed");
             var c = 0;
             while(!client.Disposed) {
                 c++;
                 if(c > 100) {
                     Assert.Fail("client was not disposed");
                 }
                 Thread.Sleep(100);
             }
         }
     }
 }
 public MemcacheClient(IPEndPoint endPoint) {
     _client = new ClacksClient(endPoint);
 }
        public void ServerSocketDisconnectTest() {
            _log.Debug("creating socket");
            var ipEndpoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), _port);
            var listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { NoDelay = true };
            listenSocket.Bind(ipEndpoint);
            listenSocket.Listen((int)SocketOptionName.MaxConnections);
            Socket requestSocket = null;

            // accept requests
            AsyncCallback onAccept = result => {
                requestSocket = listenSocket.EndAccept(result);

                // read from socket
                var receiveBuffer = new byte[5];
                if(requestSocket.Connected) {
                    requestSocket.Receive(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None);
                    requestSocket.Send(Response.Create("OK").GetBytes());
                }
            };
            listenSocket.BeginAccept(onAccept, listenSocket);
            _log.Debug("created socket");

            // create client
            using (var client = new ClacksClient("127.0.0.1", _port)) {
                Assert.IsFalse(client.Disposed);
                var response = client.Exec(new Client.Request("HELLO"));
                _log.InfoFormat("Received response with status: {0}", response.Status);
                Assert.AreEqual("OK", response.Status, "Excpected OK status");

                // disconnect server socket
                requestSocket.Shutdown(SocketShutdown.Both);
                requestSocket.Disconnect(reuseSocket: true);

                // create new socket and try another request
                listenSocket.BeginAccept(onAccept, listenSocket);
                response = client.Exec(new Client.Request("HELLO"));
                _log.InfoFormat("Received response with status: {0}", response.Status);
                Assert.AreEqual("OK", response.Status, "Excpected OK status");
            }
        }
 private void Expect_error_handler(string errorStatus, ClacksServer server) {
     using(server) {
         Console.WriteLine("created server");
         using(var client = new ClacksClient(_endpoint)) {
             Console.WriteLine("created client");
             var response = client.Exec(new Client.Request("FAIL"));
             Console.WriteLine("got response");
             Assert.AreEqual(errorStatus, response.Status);
         }
     }
 }
        public void Sync_Continous_load() {
            var statsCollector = new ClacksInstrumentation();
            var dispatcher = new SyncCommandRepository();
            dispatcher.AddCommand("BIN", request => Response.Create("OK").WithData(request.Data), DataExpectation.Auto);
            var clientHandlerFactory = new FaultingSyncClientHandlerFactory(dispatcher);
            using(new ClacksServer(new IPEndPoint(IPAddress.Parse("127.0.0.1"), _port), statsCollector, clientHandlerFactory)) {
                Console.WriteLine("created server");
                var r = new Random();
                var n = 50;
                var startSignal = new ManualResetEvent(false);
                var readySignals = new List<WaitHandle>();
                var workers = new List<Task>();
                var workerRequests = new int[n];
                var pool = ConnectionPool.Create("127.0.0.1", _port);
                var poolUseCount = 0;
                for(var i = 0; i < n; i++) {
                    var ready = new ManualResetEvent(false);
                    readySignals.Add(ready);
                    var myPool = pool;
                    var workerId = i;
                    workers.Add(Task.Factory.StartNew(() => {
                        ready.Set();
                        startSignal.WaitOne();
                        var localUseCount = 0;
                        var maxPoolUse = r.Next(50, 150);
                        while(true) {
                            localUseCount++;
                            var globalUseCount = Interlocked.Increment(ref poolUseCount);
                            if(globalUseCount > r.Next(200, 300)) {
                                Console.WriteLine("{0}: creating new pool", workerId);
                                Interlocked.Exchange(ref poolUseCount, 0);
                                pool = ConnectionPool.Create("127.0.0.1", _port);
                                myPool = pool;
                            } else if(myPool != pool && localUseCount > maxPoolUse) {
                                Console.WriteLine("{0}: picking new pool", workerId);
                                myPool = pool;
                                localUseCount = 0;
                            }
                            using(var client = new ClacksClient(myPool)) {
                                for(var k = 0; k < 1000; k++) {
                                    var payload = new StringBuilder();
                                    payload.AppendFormat("id:{0},data:", workerId);
                                    var size = r.Next(2, 100);
                                    for(var l = 0; l < size; l++) {
                                        payload.Append(Guid.NewGuid().ToString());
                                    }
                                    var data = payload.ToString();
                                    var bytes = Encoding.ASCII.GetBytes(data);
                                    Client.Response response;
                                    try {
                                        response = client.Exec(new Client.Request("BIN").WithData(bytes).ExpectData("OK"));
                                    } catch(Exception) {
                                        Console.WriteLine("request failed with data:\r\n{0}", payload);
                                        throw;
                                    }
                                    Assert.AreEqual("OK", response.Status);
                                    Assert.AreEqual(1, response.Arguments.Length);
                                    var responseData = Encoding.ASCII.GetString(response.Data);
                                    if(data != responseData) {
                                        lock(workers) {
                                            Console.WriteLine("bad data response for worker {0}", workerId);
                                            Console.WriteLine("sent:     {0}", data);
                                            Console.WriteLine("received: {0}", responseData);
                                        }
                                    }
                                    workerRequests[workerId]++;
                                    Thread.Sleep(50);
                                }
                            }
                        }
                    }));
                }
                Console.WriteLine("waiting for workers to get ready");
                WaitHandle.WaitAll(readySignals.ToArray());
                startSignal.Set();
                Console.WriteLine("starting work");
                var t = Stopwatch.StartNew();
                Task.Factory.StartNew(() => {
                    var lastRequests = new int[n];
                    Thread.Sleep(TimeSpan.FromMinutes(2));
                    while(true) {
                        var currentRequests = new int[n];
                        workerRequests.CopyTo(currentRequests, 0);
                        for(var i = 0; i < n; i++) {
                            if(currentRequests[i] == lastRequests[i]) {
                                Console.WriteLine("worker {0} has not made new requests: {1} == {2}", i, currentRequests[i], lastRequests[i]);
                            }
                        }
                        lastRequests = currentRequests;
                        Console.WriteLine("{0} Processed {1} requests with {2} faults via {3}/{4} total/active connections at {5,6:0} requests/second and {6:0.000}ms/request",
                                        DateTime.Now,
                                        statsCollector.Requests,
                                        clientHandlerFactory.Faults,
                                        statsCollector.Connected,
                                        statsCollector.Connected - statsCollector.Disconnected,
                                        statsCollector.Requests / t.Elapsed.TotalSeconds,
                                        TimeSpan.FromTicks(statsCollector.RequestTicks).TotalMilliseconds / statsCollector.Requests
                            );
                        Thread.Sleep(TimeSpan.FromMinutes(1));
                    }
                });
                Task.WaitAny(workers.ToArray());
                foreach(var worker in workers) {
                    if(worker.IsFaulted) {
                        foreach(var exception in worker.Exception.Flatten().InnerExceptions)
                            Console.WriteLine(exception);
                    }
                }
                t.Stop();
                Console.WriteLine("{0} Processed {1} requests with {2} faults via {3}/{4} total/active connections at {5,6:0} requests/second and {6:0.000}ms/request",
                                DateTime.Now,
                                statsCollector.Requests,
                                clientHandlerFactory.Faults,
                                statsCollector.Connected,
                                statsCollector.Connected - statsCollector.Disconnected,
                                statsCollector.Requests / t.Elapsed.TotalSeconds,
                                TimeSpan.FromTicks(statsCollector.RequestTicks).TotalMilliseconds / statsCollector.Requests
                    );

            }
        }
 private void QueryServer(ref string payloadstring) {
     using(var client = new ClacksClient("127.0.0.1", _port)) {
         var n = 50000;
         var t = Stopwatch.StartNew();
         for(var i = 0; i < n; i++) {
             var response = client.Exec(new Client.Request("BIN").ExpectData("OK"));
             Assert.AreEqual("OK", response.Status);
             Assert.AreEqual(1, response.Arguments.Length);
             Assert.AreEqual(payloadstring, Encoding.ASCII.GetString(response.Data));
         }
         t.Stop();
         var rate = n / t.Elapsed.TotalSeconds;
         Console.WriteLine("Executed {0} commands at {1:0}commands/second", n, rate);
     }
 }
 private void Receive_multi_response(ClacksServer server) {
     using(server) {
         Console.WriteLine("created server");
         using(var client = new ClacksClient("127.0.0.1", _port)) {
             Console.WriteLine("created client");
             var responses = client.Exec(new MultiRequest("MULTI")
                 .WithArgument("foo")
                 .WithArgument("bar")
                 .ExpectMultiple("VALUE", false)
                 .TerminatedBy("END")
             );
             Console.WriteLine("got responses");
             Assert.AreEqual(3, responses.Count());
             var r = responses.ToArray();
             Assert.AreEqual("VALUE", r[0].Status);
             Assert.AreEqual(1, r[0].Arguments.Length);
             Assert.AreEqual("foo", r[0].Arguments[0]);
             Assert.AreEqual("VALUE", r[1].Status);
             Assert.AreEqual(1, r[1].Arguments.Length, string.Join(",", r[1].Arguments));
             Assert.AreEqual("bar", r[1].Arguments[0]);
             Assert.AreEqual("END", r[2].Status);
             Assert.AreEqual(0, r[2].Arguments.Length, string.Join(",", r[2].Arguments));
         }
     }
 }
 private void Receive_multi_binary_payload(ClacksServer server) {
     using(server) {
         Console.WriteLine("created server");
         using(var client = new ClacksClient("127.0.0.1", _port)) {
             Console.WriteLine("created client");
             var responses = client.Exec(new MultiRequest("MULTI")
                 .WithArgument("foo")
                 .WithArgument("bar")
                 .ExpectMultiple("VALUE", true)
                 .TerminatedBy("END")
             );
             Console.WriteLine("got responses");
             Assert.AreEqual(3, responses.Count());
             Assert.AreEqual("VALUE", responses.ElementAt(0).Status);
             Assert.AreEqual("foo", Encoding.ASCII.GetString(responses.ElementAt(0).Data));
             Assert.AreEqual("VALUE", responses.ElementAt(1).Status);
             Assert.AreEqual("bar", Encoding.ASCII.GetString(responses.ElementAt(1).Data));
             Assert.AreEqual("END", responses.ElementAt(2).Status);
         }
     }
 }
 private void Receive_binary_payload(ClacksServer server, string payloadstring, byte[] payload) {
     using(server) {
         Console.WriteLine("created server");
         using(var client = new ClacksClient("127.0.0.1", _port)) {
             Console.WriteLine("created client");
             var response = client.Exec(new Client.Request("foo").ExpectData("OK"));
             Console.WriteLine("got response");
             Assert.AreEqual("OK", response.Status);
             Assert.AreEqual(1, response.Arguments.Length);
             Assert.AreEqual(payload.Length, response.Data.Length);
             Assert.AreEqual(payload, response.Data);
         }
     }
 }
 private void Can_send_binary_payload_with_auto_data_detection(ClacksServer server) {
     var payloadString = "blahblahblah";
     var payload = Encoding.ASCII.GetBytes(payloadString);
     using(server) {
         Console.WriteLine("created server");
         using(var client = new ClacksClient("127.0.0.1", _port)) {
             Console.WriteLine("created client");
             var response = client.Exec(new Client.Request("foo").WithData(payload));
             Console.WriteLine("got response");
             Assert.AreEqual("OK", response.Status);
             Assert.AreEqual(2, response.Arguments.Length);
             Assert.AreEqual(payload.Length.ToString(), response.Arguments[0]);
             Assert.AreEqual(payloadString, response.Arguments[1]);
         }
     }
 }
 private void EchoData(ClacksServer server) {
     using(server) {
         Console.WriteLine("created server");
         using(var client = new ClacksClient("127.0.0.1", _port)) {
             Console.WriteLine("created client");
             var response = client.Exec(new Client.Request("ECHO").WithArgument("foo").WithArgument("bar"));
             Console.WriteLine("got response");
             Assert.AreEqual("ECHO", response.Status);
             Assert.AreEqual(new[] { "foo", "bar" }, response.Arguments);
         }
     }
 }
 private void PingServer() {
     using(var client = new ClacksClient("127.0.0.1", _port)) {
         var n = 50000;
         var t = Stopwatch.StartNew();
         for(var i = 0; i < n; i++) {
             var response = client.Exec(new Client.Request("PING"));
             Assert.AreEqual("OK", response.Status);
         }
         t.Stop();
         var rate = n / t.Elapsed.TotalSeconds;
         Console.WriteLine("Executed {0} commands at {1:0}commands/second", n, rate);
     }
 }
 private void Expect_error_handler(ClacksServer server) {
     using(server) {
         Console.WriteLine("created server");
         using(var client = new ClacksClient("127.0.0.1", _port)) {
             Console.WriteLine("created client");
             var response = client.Exec(new Client.Request("FAIL"));
             Console.WriteLine("got response");
             Assert.AreEqual("ERROR", response.Status);
         }
     }
 }
 private void EchoServer() {
     using(var client = new ClacksClient("127.0.0.1", _port)) {
         var n = 50000;
         var t = Stopwatch.StartNew();
         for(var i = 0; i < n; i++) {
             var payload = new StringBuilder();
             for(var j = 0; j < 10; j++) {
                 payload.Append(Guid.NewGuid().ToString());
             }
             var bytes = Encoding.ASCII.GetBytes(payload.ToString());
             var response = client.Exec(new Client.Request("BIN").WithData(bytes).ExpectData("OK"));
             Assert.AreEqual("OK", response.Status);
             Assert.AreEqual(1, response.Arguments.Length);
             Assert.AreEqual(bytes, response.Data);
         }
         t.Stop();
         var rate = n / t.Elapsed.TotalSeconds;
         Console.WriteLine("Executed {0} commands at {1:0}commands/second", n, rate);
     }
 }
 private void Send_large_binary_payload(ClacksServer server) {
     using(server) {
         Console.WriteLine("created server");
         using(var client = new ClacksClient("127.0.0.1", _port)) {
             Console.WriteLine("created client");
             var response = client.Exec(new Client.Request("BIN").WithData(LargeBin));
             Console.WriteLine("got response");
             Assert.AreEqual("OK", response.Status);
         }
     }
 }
 private void EchoServer() {
     var n = 10000;
     var w = 50;
     var startSignal = new ManualResetEvent(false);
     var readySignals = new List<WaitHandle>();
     var workers = new List<Task>();
     var t = Stopwatch.StartNew();
     for(var j = 0; j < w; j++) {
         var id = j;
         var ready = new ManualResetEvent(false);
         readySignals.Add(ready);
         workers.Add(Task.Factory.StartNew(() => {
             using(var client = new ClacksClient("127.0.0.1", _port)) {
                 ready.Set();
                 startSignal.WaitOne();
                 for(var i = 0; i < n; i++) {
                     var payload = Guid.NewGuid().ToString();
                     var bytes = Encoding.ASCII.GetBytes(payload);
                     var response = client.Exec(new Client.Request("BIN").WithData(bytes).ExpectData("OK"));
                     Assert.AreEqual("OK", response.Status);
                     Assert.AreEqual(1, response.Arguments.Length);
                     Assert.AreEqual(bytes, response.Data);
                 }
             }
         }));
     }
     Console.WriteLine("waiting for workers to get ready");
     WaitHandle.WaitAll(readySignals.ToArray());
     startSignal.Set();
     Console.WriteLine("starting work");
     Task.WaitAll(workers.ToArray());
     t.Stop();
     var rate = n * w / t.Elapsed.TotalSeconds;
     Console.WriteLine("Executed {0} commands at {1:0}commands/second", n * w, rate);
 }
 private void Receive_large_binary_payload(ClacksServer server) {
     using(server) {
         Console.WriteLine("created server");
         using(var client = new ClacksClient("127.0.0.1", _port)) {
             Console.WriteLine("created client");
             var response = client.Exec(new Client.Request("BIN").ExpectData("OK"));
             Console.WriteLine("got response");
             Assert.AreEqual("OK", response.Status);
             Assert.AreEqual(LargeBin.Length, response.Data.Length);
             Assert.AreEqual(LargeBin, response.Data);
         }
     }
 }
Exemple #20
0
        static void Main(string[] args) {
            var workerCount = 50;
            var workerPrefix = "w";
            var faultInterval = 100000;
            var sleepInterval = 50;
            var port = new Random().Next(1000, 30000);
            var host = "127.0.0.1";
            var runServer = true;
            var poolSize = ConnectionPool.DefaultMaxConnections;
            var maxGlobalIterations = 100000;
            var options = new Options {
                {"w=", "Workers (default: 50)", x => workerCount = int.Parse(x)},
                {"P=", "Worker Prefix (default: w)", x => workerPrefix = x},
                {"S=", "Worker Pool Size (default: 100)", x => poolSize = int.Parse(x)},
                {"f=", "Fault Interval (default: every 100000)", x => faultInterval = int.Parse(x)},
                {"s=", "Sleep Interval (default: 50ms)", x => sleepInterval = int.Parse(x)},
                {"X", "Disable Server (enabled by default)", x => runServer = x == null},
                {"p=", "Server port (default: random)", x=> port = int.Parse(x)},
                {"h=", "Server host (default: 127.0.0.1)", x=> host = x},
                {"m=", "Max iterations before a new pool is created (default: 100000)", x => maxGlobalIterations = int.Parse(x)},
            };
            options.Parse(args).ToArray();
            var tasks = new List<Task>();
            if(runServer) {
                Console.WriteLine("Server: {0}:{1}", host, port);
                Console.WriteLine("starting server");
                tasks.Add(RunServer(host, port, faultInterval));
            }

            var workers = new List<WorkerInfo>(workerCount);
            if(workerCount > 0) {
                Console.WriteLine("Starting {0} workers with a {1}ms sleep interval", workerCount, sleepInterval);
                var startSignal = new ManualResetEvent(false);
                var readySignals = new List<WaitHandle>();
                var pool = ConnectionPool.Create(host, port);
                pool.MaxConnections = poolSize;
                var poolUseCount = 0;
                for(var i = 0; i < workerCount; i++) {
                    var ready = new ManualResetEvent(false);
                    readySignals.Add(ready);
                    var workerInfo = new WorkerInfo { Id = workerPrefix + i.ToString("000"), Status = WorkerStatus.PreClient };
                    workers.Add(workerInfo);
                    workerInfo.Task = Task.Factory.StartNew(() => {
                        //Thread.CurrentThread.Name = workerInfo.Id;
                        var myPool = pool;
                        var r = new Random();
                        ready.Set();
                        Console.WriteLine("{0}: ready", workerInfo.Id);
                        startSignal.WaitOne();
                        var oldPoolUse = 0;
                        var maxOldPoolIterations = r.Next(10, 100);
                        while(true) {
                            try {
                                workerInfo.Status = WorkerStatus.CheckingPool;
                                var globalUseCount = Interlocked.Increment(ref poolUseCount);
                                if(globalUseCount > maxGlobalIterations) {
                                    lock(pool) {
                                        if(pool == myPool) {
                                            Console.WriteLine("{0}: creating new pool", workerInfo.Id);
                                            Interlocked.Exchange(ref poolUseCount, 0);
                                            pool = ConnectionPool.Create(host, port);
                                            pool.MaxConnections = poolSize;
                                            myPool = pool;
                                            oldPoolUse = 0;
                                        }
                                    }
                                } else if(myPool != pool) {
                                    oldPoolUse++;
                                    if(oldPoolUse > maxOldPoolIterations) {
                                        myPool = pool;
                                        oldPoolUse = 0;
                                    }
                                }
                                using(var client = new ClacksClient(myPool)) {
                                    for(var k = 0; k < 50; k++) {
                                        workerInfo.Status = WorkerStatus.GeneratingPayload;
                                        var payload = new StringBuilder();
                                        payload.AppendFormat("id:{0},data:", workerInfo.Id);
                                        var size = r.Next(2, 100);
                                        for(var l = 0; l < size; l++) {
                                            payload.Append(Guid.NewGuid().ToString());
                                        }
                                        var data = payload.ToString();
                                        var bytes = Encoding.ASCII.GetBytes(data);
                                        workerInfo.Status = WorkerStatus.MakingRequest;
                                        var response = client.Exec(new Client.Request("BIN").WithArgument(workerInfo.Id).WithData(bytes).ExpectData("OK"));
                                        workerInfo.Status = WorkerStatus.CheckingResponse;
                                        if(response.Status != "OK") {
                                            throw new Exception("wrong status: " + response.Status);
                                        }
                                        if(response.Arguments.Length != 1) {
                                            throw new Exception("wrong arg length: " + response.Arguments.Length);
                                        }
                                        var responseData = Encoding.ASCII.GetString(response.Data);
                                        if(data != responseData) {
                                            lock(workers) {
                                                Console.WriteLine("bad data response for worker {0}", workerInfo.Id);
                                                Console.WriteLine("sent:     {0}", data);
                                                Console.WriteLine("received: {0}", responseData);
                                            }
                                        }
                                        Interlocked.Increment(ref workerInfo.Requests);
                                    }
                                }
                                workerInfo.Status = WorkerStatus.Sleeping;
                                Thread.Sleep(sleepInterval);
                            } catch(Exception e) {
                                workerInfo.Status = WorkerStatus.Failed;
                                Console.WriteLine("{0} failed: [{1}] {2}", workerInfo.Id, e.GetType(), e.Message);
                                Thread.Sleep(sleepInterval);
                            }
                        }
                    });
                    tasks.Add(workerInfo.Task);
                }
                Console.WriteLine("waiting for workers to get ready");
                WaitHandle.WaitAll(readySignals.ToArray());
                startSignal.Set();
                Console.WriteLine("starting work");
            }
            var t = Stopwatch.StartNew();
            Thread.Sleep(TimeSpan.FromMinutes(1));
            var lastRequests = workers.ToDictionary(k => k.Id, v => v.Requests);
            var requests = new Queue<Tuple<int, TimeSpan>>();
            while(true) {
                if(workerCount > 0) {
                    var total = workers.Sum(x => x.Requests) - lastRequests.Values.Sum();
                    requests.Enqueue(new Tuple<int, TimeSpan>(total, t.Elapsed));
                    if(requests.Count > 5) {
                        requests.Dequeue();
                    }
                    var rate = requests.Aggregate((a, b) => new Tuple<int, TimeSpan>(a.Item1 + b.Item1, a.Item2 + b.Item2));
                    Console.WriteLine("{0} Executing requests at {1:0} requests/second",
                                      DateTime.Now,
                                      rate.Item1 / rate.Item2.TotalSeconds
                        );
                    foreach(var stuckGroup in from worker in workers
                                              where worker.Requests == lastRequests[worker.Id]
                                              let x = new { worker.Id, worker.Requests, worker.Status }
                                              group x by x.Status
                                                  into xg
                                                  select new { Status = xg.Key, Workers = xg }) {
                        Console.WriteLine("  {0} workers stuck in '{1}': {2}",
                                      stuckGroup.Workers.Count(),
                                      stuckGroup.Status,
                                      string.Join(", ", from worker in stuckGroup.Workers orderby worker.Id select string.Format("{0} ({1})", worker.Id, worker.Requests))
                            );
                    }
                    foreach(var worker in workers) {
                        lastRequests[worker.Id] = worker.Requests;
                    }
                    t.Restart();
                }
                Thread.Sleep(TimeSpan.FromMinutes(1));
            }
        }
 public void Async_Multi_Response_Handler_with_single_callback_is_called_exactly_once_per_request() {
     var requestCount = 0;
     using(ServerBuilder.CreateAsync(new IPEndPoint(IPAddress.Parse("127.0.0.1"), _port))
         .WithCommand("PING")
             .ExpectsNoData()
                 .HandledBy((request, responseCallback) => {
                     requestCount++;
                     responseCallback(new[] { Response.Create("PONG"), Response.Create("END") });
                 })
             .Register()
         .Build()
         ) {
         _log.Debug("created server");
         using(var client = new ClacksClient("127.0.0.1", _port)) {
             _log.Debug("created client");
             client.Exec(new MultiRequest("PING")
                 .ExpectMultiple("PONG", false)
                 .TerminatedBy("END"));
             _log.Debug("got response");
             Assert.AreEqual(1, requestCount);
         }
     }
 }