jgauffin / Griffin.Framework

Application framework for Business Applications
http://griffinframework.net
168 stars 63 forks source link

HttpListener - ListenerError - PoolEmptyException #88

Open mjtvulcan opened 5 years ago

mjtvulcan commented 5 years ago

I'm using the HttpListener process. I'm load testing to check stability. Basically firing one request after another, and then multiple sessions firing multiple requests. I'm finding that the HttpListener triggers a ListenerError event - this seems to be caused by the following exception:

Griffin.Net.Buffers.PoolEmptyException

At this point the listening stops, and no further requests can be made.

From digging through the source I can see this is to do with thread safe concurrentstack use - just can't see the fix.

My code is pretty straight forward... var listenerInternal = new Griffin.Net.Protocols.Http.HttpListener(); listenerInternal.MessageReceived += OnMessageReceived; listenerInternal.ListenerError += OnListenerError; listenerInternal.MessageSent += OnMessageSent; listenerInternal.BodyDecoder = new Serializers.PlainTextSerializer();

` private static void OnMessageReceived(ITcpChannel channel, object message) { try { //Thread.CurrentThread.Name = string.Format("{0}:{1}", DateTime.Now.ToShortDateString(), messageCounter); Thread.CurrentThread.Name = Guid.NewGuid().ToString("N"); var request = (HttpRequest)message;

            log.InfoFormat("{0} {1}", request.HttpMethod, request.StatusLine);
            bool internalRequest = clsUtils.IsLocalIpAddress((System.Net.IPEndPoint)request.RemoteEndPoint); //ignore this one
            internalRequest = clsUtils.isIPLocal(((System.Net.IPEndPoint)request.RemoteEndPoint).Address);

            var response = (HttpResponse)request.CreateResponse();
            using (RequestHandler r = new RequestHandler(ref channel, ref message, internalRequest))
            {
                response = r.getResponse();
                channel.Send(response);
                if (request.HttpVersion == "HTTP/1.0")
                    channel.Close();
                r.waitForTasks();
            }

The RequestHandler has been super simplified to just return something quick and meaningless public RequestHandler(ref ITcpChannel channel, ref object message, bool internalRequest) { var incomingMessage = new IncomingMessage(); var data = ""; var NVP = new System.Collections.Specialized.NameValueCollection(); request = (HttpRequest)message; response = (HttpResponse)request.CreateResponse();

        ////////////////////////////////////////////////
        response.StatusCode = (int)HttpStatusCode.OK;
        response.Body = new MemoryStream(Encoding.UTF8.GetBytes(string.Format("Up and running\nProcessed {0} requests", requestCount)));
        response.ContentType = "text/plain";
        return;
    }`

I'm using the latest Griffin.Framework nuget v2.1.1 Can you see where i'm going wrong?

It looks like either a process that should be cleaning up isn't, or i'm just doing too much - In these recent tests, it probably amounts to 7 sessions processing 20 or so requests one after the other.

image

Thanks for your help.

jgauffin commented 4 years ago

My new networking code is almost done. It will solve many of the concurrency issues that existed with the old code.

Here is a same on how the new http server is configured:

https://github.com/jgauffin/Griffin.Framework/blob/new_networking_code/src/Griffin.Framework/HttpServerTests/Program.cs

(Although it's not working just yet, I'm going through all tests now)