TimeOuts с HttpWebRequest при одновременном запуске Selenium в .NET - PullRequest
0 голосов
/ 24 марта 2010

У меня есть загрузчик, который использует ThreadPool-потоки для загрузки файлов. Усовершенствовав их, чтобы применить некоторые тесты Selenium к загруженным файлам, я постоянно испытываю исключения TimeOut с загрузчиками файлов и задержки с запуском тестов Selenium. Точнее:

  • Когда программа запускается, потоки загрузки начинают загружаться, и несколько страниц легко обрабатываются с помощью Selenium
  • Вскоре после этого первые потоки загрузки начинают генерировать исключения TimeOut из HttpWebRequest.
  • В то же время команды перестают поступать в Selenium (как указано в журнале SeleniumRC), но поток, выполняющий Selenium, не получает никаких исключений
  • Эта ситуация сохраняется до тех пор, пока в списке загрузки есть записи: новые потоки загрузки запускаются и завершаются после получения TimeOuts (без попытки блокировки Selenium)
  • Как только больше не загружаются потоки загрузки, Selenium снова начинает получать команды, и потоки, ожидающие блокировки, обрабатываются последовательно, как задумано

Теперь вот код загрузки:

HttpWebRequest request = null;
WebResponse response = null;
Stream stream = null;
StreamReader sr = null;
try
{
    request = (HttpWebRequest) WebRequest.Create(uri);
    request.ServicePoint.ConnectionLimit = MAX_CONNECTIONS_PER_HOST;
    response = request.GetResponse();
    stream = response.GetResponseStream();
    // Read the stream...
}
finally
{
    if (request != null) request.Abort();
    if (response != null) response.Close();
    if (stream != null)
    {
        stream.Close();
        stream.Dispose();
    }
    if (sr != null)
    {
        sr.Close();
        sr.Dispose();
    }
}

И вот как Selenium впоследствии используется в той же теме:

lock(SeleniumLock)
{
    selenium.Open(url);
    // Run some Selenium commands, but no selenium.stop()
}

Где selenium - статическая переменная, которая инициализируется в статическом конструкторе класса (через selenium.start()).

Я предполагаю, что я нахожусь в пределе соединения CLR, поэтому я добавил эти строки во время инициализации:

ThreadPool.GetMaxThreads (out maxWorkerThreads, out maxCompletionPortThreads);
HttpUtility.MAX_CONNECTIONS_PER_HOST = maxWorkerThreads;
System.Net.ServicePointManager.DefaultConnectionLimit = maxWorkerThreads + 1;

+ 1 - для подключения к SeleniumRC, из-за того, что я думаю, что клиентский код Selenium также использует HttpWebRequest. Похоже, я все еще сталкиваюсь с каким-то тупиком - хотя потоки, ожидающие блокировки Selenium, не удерживают никаких ресурсов.

Есть идеи, как заставить это работать?

1 Ответ

1 голос
/ 27 марта 2010

После более глубокого изучения этой проблемы я понял, что проблема связана не с соединениями, а с ThreadPool и HttpWebRequest: в момент времени, когда загрузчики начинают испытывать таймауты, ThreadPool.GetAvailableThreads() возвращает 0 или -1 доступных рабочих потоков. , Я тщательно выбрал синхронное использование HttpWebRequest, чтобы этого не произошло. Предположительно, клиентский драйвер Selenium вместо этого использует асинхронные методы, что приводит к такому типу «взаимоблокировки потоков».

Я не уверен, что будет лучшим способом решить эту проблему, но эта обходная замена для ThreadPool.QueueUserWorkItem() делает программу пригодной для использования как минимум:

protected void QueueWorkItem(WaitCallback callBack, object state)
{
    // Wait for available thread (as Selenium's async I/O is mixed with ThreadPool and yields deadlocks)
    int b, c;
    do
    {
        ThreadPool.GetAvailableThreads(out b, out c);
        if (b < 10) Thread.Sleep(250);
    } while (b < 10);
    // Queue the work item
    if (ThreadPool.QueueUserWorkItem(callBack, state)) Interlocked.Increment(ref WorkItemCount);
}
...