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); } } } }
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 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); } }
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 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 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 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 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); } } }
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); } } }