Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c# comet server freezing IIS

Tags:

c#

.net

iis

comet

I'm making my first attempt at experimenting with Comet. I developed a very simple chat web app - basically a hello world of comet via c#. The problem i'm having is IIS will sometimes crash and by crash i mean it simply stops responding to HTTP requests. It then takes for ever to restart the app pool and sometimes the whole IIS service. I'm almost positive the culprit is the ManualResetEvent object I'm using to block comet requests threads until a signal to release (update) those threads is received. I tried writing an HTTP handler to get around this and set the reusable property to false (to put new requests threads on another instance of the ManualResetEvent object) but that didn't work. I'm also trying implementing the IRegisteredObject so I can release those theads when the app is shutting down but that doesn't seem to work either. It still crashes and there doesn't seem to be any pattern in when it crashes (that i've noticed). I'm almost sure it's a combination of static instances and the use of ManualResetEvent that's causing it. I just don't know for sure how or how to fix it for that matter.

Comet.cs (My simple comet lib)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net.Mail;
using System.Web.Hosting;

namespace Comet
{
    public class CometCore : IRegisteredObject
    {
        #region Globals
        private static CometCore m_instance = null;
        private List<CometRequest> m_requests = new List<CometRequest>();
        private int m_timeout = 120000; //Default - 20 minutes;
        #endregion

        #region Constructor(s)
        public CometCore()
        {
            HostingEnvironment.RegisterObject(this);
        }
        #endregion

        #region Properties
        /// <summary>
        /// Singleton instance of the class
        /// </summary>
        public static CometCore Instance
        {
            get
            {
                if (m_instance == null)
                    m_instance = new CometCore();
                return m_instance;
            }
        }

        /// <summary>
        /// In milliseconds or -1 for no timeout.
        /// </summary>
        public int Timeout { get { return m_timeout; } set { m_timeout = value; } }
        #endregion

        #region Public Methods
        /// <summary>
        /// Pauses the thread until an update command with the same id is sent.
        /// </summary>
        /// <param name="id"></param>
        public void WaitForUpdates(string id)
        {
            //Add this request (and thread) to the list and then make it wait.
            CometRequest request;
            m_requests.Add(request = new CometRequest(id));

            if (m_timeout > -1)
                request.MRE.WaitOne(m_timeout);
            else
                request.MRE.WaitOne();
        }

        /// <summary>
        /// Un-pauses the threads with this id.
        /// </summary>
        /// <param name="id"></param>
        public void SendUpdate(string id)
        {
            for (int i = 0; i < m_requests.Count; i++)
            {
                if (m_requests[i].ID.Equals(id))
                {
                    m_requests[i].MRE.Set();
                    m_requests.RemoveAt(i);
                    i--;
                }
            }
        }
        #endregion

        public void Stop(bool immediate)
        {
            //release all threads
            for (int i = 0; i < m_requests.Count; i++)
            {
                m_requests[i].MRE.Set();
                m_requests.RemoveAt(i);
                i--;
            }
        }
    }

    public class CometRequest
    {
        public string ID = null;
        public ManualResetEvent MRE = new ManualResetEvent(false);
        public CometRequest(string pID) { ID = pID; }
    }
}

My chat class and web service

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using Comet;

namespace CometTest
{
    /// <summary>
    /// Summary description for Chat
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    [System.Web.Script.Services.ScriptService]
    public class Chat : System.Web.Services.WebService
    {

        [WebMethod]
        public string ReceiveChat()
        {
            return ChatData.Instance.GetLines();
        }

        [WebMethod]
        public string ReceiveChat_Comet()
        {
            CometCore.Instance.WaitForUpdates("chat");
            return ChatData.Instance.GetLines();
        }

        [WebMethod]
        public void Send(string line)
        {
            ChatData.Instance.Add(line);
            CometCore.Instance.SendUpdate("chat");
        }
    }

    public class ChatData
    {
        private static ChatData m_instance = null;
        private List<string> m_chatLines = new List<string>();
        private const int m_maxLines = 5;

        public static ChatData Instance
        {
            get
            {
                if (m_instance == null)
                    m_instance = new ChatData();
                return m_instance;
            }
        }

        public string GetLines()
        {
            string ret = string.Empty;
            for (int i = 0; i < m_chatLines.Count; i++)
            {
                ret += m_chatLines[i] + "<br>";
            }
            return ret;
        }

        public void Add(string line)
        {
            m_chatLines.Insert(0, line);
            if (m_chatLines.Count > m_maxLines)
            {
                m_chatLines.RemoveAt(m_chatLines.Count - 1);
            }
        }
    }
}

The test aspx file

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CometTest.Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">

        <asp:ScriptManager ID="ScriptManager1" runat="server">
            <Services>
                <asp:ServiceReference Path="~/Chat.asmx" />
            </Services>
        </asp:ScriptManager>

        <div id="lyrChatLines" style="height: 200px; width: 300px; border: 1px solid #cccccc; overflow: scroll">
        </div>

        <asp:Panel runat="server" DefaultButton="cmdSend">
            <asp:UpdatePanel runat="server">
                <ContentTemplate>
                    <asp:TextBox style="width: 220px" runat="server" ID="txtChat"></asp:TextBox>
                    <asp:Button runat="server" ID="cmdSend" Text="Send" OnClick="cmdSend_Click" />
                </ContentTemplate>
            </asp:UpdatePanel>
        </asp:Panel>

        <script type="text/javascript">

            function CometReceive()
            {
                CometTest.Chat.ReceiveChat_Comet(receive, commError, commError);
            }

            function ReceiveNow()
            {
                CometTest.Chat.ReceiveChat(receive, commError, commError);
            }

            function receive(str)
            {
                document.getElementById("lyrChatLines").innerHTML = str;
                setTimeout("CometReceive()", 0);
            }

            function commError()
            {
                document.getElementById("lyrChatLines").innerHTML =
                    "Communication Error...";
                setTimeout("CometReceive()", 5000);
            }

            setTimeout("ReceiveNow()", 0);
        </script>
    </form>
</body>
</html>

And the aspx code behind

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace CometTest
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void cmdSend_Click(object sender, EventArgs e)
        {
            Chat service = new Chat();
            service.Send
            (
                Request.UserHostAddress + "> " +
                txtChat.Text
            );
            txtChat.Text = string.Empty;
            txtChat.Focus();
        }
    }
}

If anyone has a good theory on the cause and/or fix for the seemingly arbitrary crashes it would be much appreciated if you'ld post :)

like image 833
Stewart Anderson Avatar asked Nov 13 '22 21:11

Stewart Anderson


1 Answers

This question .NET Comet engine has some links that should point you in the right direction. You need to look at implementing a IHttpAsyncHandler to handle the long running comet request.

like image 112
snoopy-do Avatar answered Dec 19 '22 01:12

snoopy-do