2015-05-07 7 views
5

Когда я использую следующий сценарий:Luasocket + Nginx ошибки - Lua запись прервана нить: ошибка во время выполнения: попытка уступить через границу C вызова

local smtp = require("socket.smtp") 
local from = "[email protected]" 
local rcpt = "[email protected]" 
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.

Я использую новейший luasocket, установленный с luarocks с Lua 5.1 с использованием nginx, скомпилированного с LuaJIT 2.1. Что вызывает это сообщение об ошибке и как его исправить?

+0

У вас есть полный пример, который мы можем подключить к 'content_by_lua_file', чтобы увидеть, где он не работает? Не работает ли строка 'smtp.send' или' require'? Я подозреваю, что это первый, но хотел бы подтвердить. –

+0

Это в значительной степени полный пример. Он не работает при отправке. – arby

ответ

4

smtp.send использует функцию LuaSocket socket.protect для обработки внутренних ошибок. Эта функция реализована на языке C и не позволяет уступать текущим выпускам (версия в git HEAD теперь позволяет давать на Lua 5.2+, см. Обсуждение here). Видимо, кто-то пытается уступить изнутри. В etc/dispatch.lua в пакете LuaSocket (лучше использовать версию git HEAD) есть replacement function for socket.protect, что должно позволить уступать во всех версиях Lua (за счет дополнительной временной сопрограммы). Вы можете попробовать заменить функцию C такой функцией Lua, как показано ниже:

+0

«Кто-то пытается уступить изнутри» - суть проблемы. Если тот же скрипт работает из автономного LuaJIT с использованием пакета luasocket, он должен быть связан с ngx_lua. В моем случае проблема заключалась в том, что была использована библиотека сокетов ngx_lua (что делает неявный доход), и исправление заключалось в использовании библиотеки luasocket. –

+0

Ликвидация 'yield' также решит проблему. Но как вы это делаете? Модуль socket.smtp уже пытается загрузить функции LuaSocket по умолчанию через 'require (" socket ")' - он даже не знает о версиях Nginx. Как вы препятствуете Nginx заменять внутренние функции LuaSocket (по-видимому)? Даже если вы справитесь, исходные функции LuaSocket блокируются (вероятно, поэтому Nginx реализует свой собственный планировщик на основе сопрограмм). – siffiejoe

2

Я видел это сообщение в несколько схожей ситуации; в моем случае это было связано с дизайном ngx_lua, который реализует собственный планировщик сопрограмм. Это означает, что sock:receive не блокирует, а вместо этого делает неявное yield планировщику, и в результате, если вызов sock:receive сделан с функцией C, находящейся в стеке, вы, скорее всего, получите ошибку, которую видите.

В моем случае я делал вызов sock:receive с помощью отладочного крючка и получал эту ошибку, пока не перешел на использование методов сокетов из моей собственной версии luasocket, которая не дает. Я бы проверял, использует ли socket.smtp «нормальную» версию luasocket.

4

Это связано с совместным использованием LuaJIT и socket.smtp, который вращает сопрограмму. От https://github.com/openresty/lua-nginx-module/issues/376:

@AterCattus This is a known limitation in LuaJIT (and the standard Lua 5.1 interpreter) that the require() builtin is currently implemented as a C builtin across which you cannot initiate a yield.

Похоже, что лучший способ может быть, чтобы использовать эту реализацию require.lua: https://github.com/pygy/require.lua. Это написано в чистом Lua вместо C, чтобы обойти эту проблему с LuaJIT.

+0

Хм, я загрузил 'require-lua 0.1.7-2' и установил через luarocks, а затем поставил' require = require 'потребовать «.require' в верхней части моего скрипта. Я все равно получаю ту же ошибку: «попытайтесь получить границу C-вызова» из функции smtp.send. – arby

+0

arby, похоже, что ответ @ siffiejoe здесь правильный. Если socket.protect написан на C, то это настоящая основная проблема! –