Сбой Haskell System.Timeout.timeout при вызове из определенной функции - PullRequest
0 голосов
/ 30 марта 2011

Я собираю некоторые данные с первых страниц списка доменов сайта. Некоторые из них не отвечают или работают очень медленно, что приводит к остановке скребка.

Я хотел решить эту проблему, используя тайм-аут. Различные доступные библиотеки HTTP, кажется, не поддерживают это, но System.Timeout.timeout, кажется, делает то, что мне нужно.

Действительно, кажется, что он работает нормально, когда я тестирую функцию очистки, но он вылетает, как только я запускаю включающую функцию: (Извините за плохой / уродливый код. Я учусь.)

    fetchPage domain =
      -- Try to read the file from disk.
      catch
        (System.IO.Strict.readFile $ "page cache/" ++ domain)
        (\e -> downloadAndCachePage domain)


    downloadAndCachePage domain =
      catch
        (do
          -- Failed, so try to download it.

    -- This craches when called by fetchPage, but works fine when called from directly.
          maybePage <- timeout 5000000 (simpleHTTP (getRequest ("http://www." ++ domain)) >>= getResponseBody)
          let page = fromMaybe "" maybePage

    -- This mostly works, but wont timeout if the domain is slow. (lswb.com.cn)
    --      page <- (simpleHTTP (getRequest ("http://www." ++ domain)) >>= getResponseBody)

          -- Cache it.
          writeFile ("page cache/" ++ domain) page
          return page)
        (\e -> catch
          (do
            -- Failed, so just fuggeddaboudit.
            writeFile ("page cache/" ++ domain) ""
            return "")
          (\e -> return "")) -- Failed BIG, so just don't give a crap.

downloadAndCachePage прекрасно работает с таймаутом при вызове из repl, но fetchPage вылетает. Если я удаляю тайм-аут из downloadAndCachePage, fetchPage будет работать.

Кто-нибудь, кто может объяснить это или знает альтернативное решение?

1 Ответ

1 голос
/ 30 марта 2011

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

В общем, вы должны помещать как можно меньше кода в обработчики исключений и особенно не помещать код, который пытается обрабатывать дальнейшие исключения (хотя этокак правило, можно вызвать обработанное исключение, чтобы «передать его» [как в случае bracket]).

При этом, даже если вы делаете не то, что нужно, происходит сбой (если этосбой типа segfault (в отличие от сбоя типа <<loop>>), даже из странного кода, почти всегда является неправильным поведением GHC, и если вы работаете в GHC 7, вам следует сообщить об этом.

...