Luasocket + nginx 错误 - Lua 入口线程中止:运行时错误:试图跨 C 调用边界进行 yield。

当我运行以下脚本时:

local smtp = require("socket.smtp")
local from = "from@host"
local rcpt = "rcpt@host"
local msg = {
  headers = {
    to = rcpt,
    subject = "Hi"
  },
  body = "Hello"
}
smtp.send{from = from,rcpt = rcpt,source = smtp.message(msg)}

我会收到错误消息:lua entry thread aborted: runtime error: attempt to yield across C-call boundary

我使用最新的luarocks安装的luasocket,使用LuaJIT 2.1编译的nginx和Lua 5.1。是什么导致了这个错误消息,我该如何修复它?

点赞
用户1442917
用户1442917

我在一个类似的情况下看到过这条消息;在我的情况下,它与 ngx_lua 的设计有关,它实现了自己的协程调度器。这意味着 sock:receive 不会阻塞,而是隐式地给调度器 yield。因此,如果在堆栈上有一个 C 函数时调用 sock:receive,则很可能会出现你看到的错误。

在我的情况下,我从调试钩子中调用了 sock:receive,直到我切换到使用自己版本的 luasocket 的套接字方法,它不会进行 yield,我才不再遇到此错误。我建议检查 socket.smtp 是否使用了“正常”的 luasocket 版本。

2015-05-08 15:43:02
用户300290
用户300290

这是由于 LuaJIT 和 socket.smtp 结合使用,它们会启动一个协程。来源于 https://github.com/openresty/lua-nginx-module/issues/376:

@AterCattus 这是 LuaJIT(和标准 Lua 5.1 解释器)的已知限制,require()内置当前实现为 C 内置,不能在其中启动 yield。

看起来最好的解决方法是使用这个 require.lua 实现: https://github.com/pygy/require.lua。它是用纯 Lua 编写的,而不是 C,以解决 LuaJIT 的这个问题。

2015-05-13 14:37:20
用户3677376
用户3677376

smtp.send 使用 LuaSocket 的 socket.protect 函数来处理内部错误。这个函数是用 C 实现的,目前的版本不允许在当前的版本中使用 yielding(与此处的讨论见 这里)。显然有人试图从其中进行 yielding。在 LuaSocket 包的 etc/dispatch.lua 中(最好使用 git HEAD 版本),有一种替换 socket.protect 的函数,它应该允许在所有 Lua 版本中进行 yielding(代价是多一个临时 coroutine)。您可以尝试这样用 Lua 函数替换 C 函数:

local socket = require("socket")
local base = _G
-- paste modified socket.protect function here

-- continue with your own code:
local smtp = require("socket.smtp")
-- ...
2015-05-14 06:53:20