从某些函数调用时,Haskell System.Timeout.timeout崩溃

时间:2011-03-30 11:03:23

标签: http haskell crash timeout io

我正在从网站域名列表的前端抓取一些数据。他们中的一些人没有回答,或者说很慢,导致刮刀停止。

我想通过使用超时来解决这个问题。可用的各种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.
当从repl调用时,

downloadAndCachePage可以正常使用超时,但是fetchPage崩溃了。如果我从downloadAndCachePage中删除超时,fetchPage将起作用。

任何能够解释这一点或知道替代解决方案的人?

1 个答案:

答案 0 :(得分:1)

你在fetchPage中的catch处理程序看起来是错误的 - 看起来你正在尝试读取一个文件,而在文件中找不到异常会直接从异常处理程序调用你的http函数。不要这样做。由于复杂的原因,我记得,异常处理程序中的代码并不总是像普通代码一样 - 特别是当它试图自己处理异常时。实际上,在底层,超时使用异步异常来杀死线程。

通常,您应该在异常处理程序中放置尽可能少的代码,尤其不要放置尝试处理进一步异常的代码(尽管将处理的异常重新加载到“传递它”通常很好[与{一样] {1}}])。

也就是说,即使你没有做正确的事情,崩溃(如果它是一个段错误类型崩溃而不是bracket类型崩溃),即使是奇怪的代码,也几乎总是错误的行为来自GHC,如果您使用GHC 7,那么您应该考虑报告此事。