uniqman Ответов: 1

Поток веб-службы умирает сразу после запуска на одном сервере


I have developed an ASP.NET (.asmx) webservice in C#. Just before it returns, it starts a thread (have tried via the threadpool and a simple thread) to perform a web request. Before creating the web request, I need a delay of about 1 - 2 seconds. I have tried a Sleep, a Timer, and even a for loop counting into the millions. On my development server (Server 2012 R2) it works all of the time. On the customer's server thousands of miles away in a different country, but also on Server 2012 R2, it works less than 10% of the time. According to my logging, the thread ends sometime during the delay, before the web request. What could be killing it? Does ASP.NET decide it is not active?

Code:



I have developed an ASP.NET (.asmx) webservice in C#. Just before it returns, it starts a thread to perform a web request. Before creating the web request, I need a delay of about 2 seconds. I have tried a Sleep, a Timer, and even a for loop counting into the millions. On my development server it works all of the time. On the customer's server, it works less than 10% of the time. According to my logging, the thread ends sometime during the delay, before the web request. What could be killing it? Does ASP.NET decide it is not active?
It logs "TesterRequest: Before WAIT of" then the System exception "Thread was being aborted" (see code below), then of course nothing else.
Relevant Code - Below is the for loop version (put in the for loop just to test after sleep and timer methods failed to be sustained, were aborted before elapsed time was completed): 

static void ThreadProc(object p_tcti)
{

        // Calls a method inside the tester via HttpWebRequest

            int nSleep = 606111000; // 2000;
            LogMessage(DateTime.Now.ToString() + " ms: " + DateTime.Now.Millisecond.ToString() + ". " + "TesterRequest: Before WAIT of " + nSleep.ToString());

            int nDummy = 0;
            for (int n = 0; n < nSleep; n++)
            {
                nDummy = n;
            }

            LogMessage(DateTime.Now.ToString() + " ms: " + DateTime.Now.Millisecond.ToString() + ". " + "TesterRequest: After WAIT " + nDummy.ToString() + " creating web request to tester.");
            HttpWebRequest reqWeb = (HttpWebRequest)WebRequest.Create(tcti.m_strURL);
            LogMessage(DateTime.Now.ToString() + " ms: " + DateTime.Now.Millisecond.ToString() + ". " + "TesterRequest: Created the web request.");
            reqWeb.Method = "GET";
            //reqWeb.MaximumAutomaticRedirections = 4;
            //reqWeb.MaximumResponseHeadersLength = 4;
            reqWeb.UserAgent = "ABRWebService /1.0";
            // Do it!  This will block for up to 40 seconds
            string strStatus = "";
            reqWeb.Timeout = 40000;
     try
     {
                HttpWebResponse resWeb = (HttpWebResponse)reqWeb.GetResponse();
                //       LogMessage(DateTime.Now.ToString() + " ms: " + DateTime.Now.Millisecond.ToString() + ". " + "TesterRequest: Received response from the tester web request. ");
                if (resWeb.StatusCode != HttpStatusCode.OK)
                {
                    strStatus = resWeb.StatusDescription;
                    LogMessage(DateTime.Now.ToString() + " ms: " + DateTime.Now.Millisecond.ToString() + ". " + "TesterRequest FAILED" + " " + strStatus);
                }
                resWeb.Close();
            }
            catch (WebException we)
            {
                // Ignore timeouts since we don't give a about the
                // response.
                tcti.m_strResult = we.Message;
                if (we.Status != WebExceptionStatus.Timeout)
                {
                    LogMessage(DateTime.Now.ToString() + " ms: " + DateTime.Now.Millisecond.ToString() + ". " + "TesterRequest Web Exception:  " + we.Message + "  Request:  " +
                    tcti.m_strResult + ", URL:  " + tcti.m_strURL);
                    if (!strStatus.Equals(""))
                        LogMessage("Status: " + strStatus);
                    LogMessage("TesterRequest FAILED" + " " + DateTime.Now);
                    // RWC don't throwthrow we;
                }
            }
            catch (Exception ex)
            {
                LogMessage(DateTime.Now.ToString() + " ms: " + DateTime.Now.Millisecond.ToString() + ". " + "TesterRequest Exception:  " + ex.Message);
            }

            LogMessage(DateTime.Now.ToString() + " ms: " + DateTime.Now.Millisecond.ToString() + ". " + "TesterRequest Succeeded.");

}

public TesterRequest(string p_strURL)
{       {
  try
  {
                TesterCommThreadInfo tcti = new TesterCommThreadInfo();
                tcti.m_strURL = p_strURL;
                   LogMessage(DateTime.Now.ToString() + " ms: " + DateTime.Now.Millisecond.ToString() + ". " + "TesterRequest: Begin queueing a thread to trigger program download.");
                   ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), tcti);
               // Service.LogMessage(DateTime.Now.ToString() + " ms: " + DateTime.Now.Millisecond.ToString() + ". " + "TesterRequest: Begin - Create and launch a new thread to trigger program download.");
                // 6/4/18 changed to simple thread from thread pool for better reliability.
                //Thread tr = new Thread(() => ThreadProc(tcti));
                //tr.Start();
                //Service.LogMessage(DateTime.Now.ToString() + " ms: " + DateTime.Now.Millisecond.ToString() + ". " + "TesterRequest: End - Create and launch a new thread to trigger program download.");
                   LogMessage(DateTime.Now.ToString() + " ms: " + DateTime.Now.Millisecond.ToString() + ". " + "TesterRequest: End queued a thread to trigger program download.");
            }
            catch (ThreadAbortException tae)
            {
                Service.LogMessage(DateTime.Now.ToString() + " ms: " + DateTime.Now.Millisecond.ToString() + ". " + "TesterRequest Thread Abort Exception Creating and/or launching new thread for program download: " + tae.Message);
            }
            catch (AppDomainUnloadedException aue)
            {
                Service.LogMessage(DateTime.Now.ToString() + " ms: " + DateTime.Now.Millisecond.ToString() + ". " + "TesterRequest App Domain Unloaded Exception Creating and/or launching new thread for program download: " + aue.Message);
            }
            catch (Exception ex)
            {
                Service.LogMessage(DateTime.Now.ToString() + " ms: " + DateTime.Now.Millisecond.ToString() + ". " + "TesterRequest Exception Creating and/or launching new thread for program download: " + ex.Message);
            }
        }
    }
}

What I have tried:

Tried changing from threadpool thread to simple thread. Tried three different delays. First delay was a System Threading Thread Sleep. Then I attempted a System Timer. Finally, in a strong attempt to eliminate the appearance my thread was inactive, I used a for loop counting into the millions for the dealy.

1 Ответов

Рейтинг:
0

Dave Kreskowiak

Ваш ASP.NET код выполняется только в течение времени, необходимого для выполнения входящего запроса. Если вы "выстрелите и забудете" нить, эта нить будет прервана один раз ASP.NET возвращает ответ клиенту.

Ваш код должен дождаться, пока поток завершит свою работу, прежде чем возвращать что-либо клиенту.


uniqman

Спасибо за ваш ответ. Но можете ли вы объяснить, как это работает 100% времени на моем сервере 2012 R2 и 10% -50% времени на клиентах же? Мы смогли перейти от 10% до 50%, сократив задержку с 2 секунд до примерно 600 мс.

uniqman

Кроме того, я забыл упомянуть в первоначальной публикации, что этот порождающий поток код и сам код потока были заимствованы из веб-приложения, которое всегда хорошо работало для отправки файлов на наше тестовое оборудование.

Dave Kreskowiak

Нет, потому что я абсолютно ничего не знаю о вашем коде. Я только дал вам "пример", чтобы вы подумали.