If your host system is Linux/Unix-like, then you could run a helper
daemon process, which listens locally on a unix socket and spawns
a child process to execute the shell command that you provide.
I needed this for one of my projects, so i wrote a simple implementation of it:
https://github.com/juce/sockproc
Seems to work pretty well. Your shell module in Lua then becomes very simple:
it uses co-socket API to talk to the sockproc daemon, and therefore is
completely non-blocking:
-- Non-blocking replacement for os.execute
local shell = {}
local sockproc_socket = "unix:/tmp/hello.sock"
function shell.execute(cmd, args)
local timeout = args and args.timeout
local input_data = args and args.data or ""
local sock = ngx.socket.tcp()
local ok, err = sock:connect(sockproc_socket)
if ok then
sock:settimeout(timeout or 15000)
sock:send(cmd .. "\r\n")
sock:send(string.format("%d\r\n", #input_data))
sock:send(input_data)
-- status code
local data, err, partial = sock:receive('*l')
if err then
return -1, nil, err
end
local code = string.match(data,"status:([-%d]+)") or -1
-- output stream
data, err, partial = sock:receive('*l')
if err then
return -1, nil, err
end
local n = tonumber(data) or 0
local out_bytes = n > 0 and sock:receive(n) or nil
-- error stream
data, err, partial = sock:receive('*l')
if err then
return -1, nil, err
end
n = tonumber(data) or 0
local err_bytes = n > 0 and sock:receive(n) or nil
sock:close()
return tonumber(code), out_bytes, err_bytes
end
return -2, nil, err
end
return shell
On Tuesday, December 3, 2013 2:51:44 PM UTC-8, agentzh wrote:
Hello!
On Tue, Dec 3, 2013 at 2:25 PM, Ivan Ribeiro wrote:
> Please, I need something similar to os.execute or io.popen to call a
> program from my lua script and check the result status or the stdout. When I
> use both, I get a message like this:
>
> 2013/12/03 20:10:14 [info] 8239#0: waitpid() failed (10: No child
> processes)
>
In short: don't do that.
os.execute and io.popen will both block your nginx worker processes
(possibly for long), which will kill the overall performance.
That info message itself is usually harmless because os.execute and
io.popen both spawn new child processes. We can reduce the number of
this messages by explicitly calling close() as soon as possible in
your Lua code for the file returned by io.popen().
I have a plan of implementing a nonblocking pipe API in ngx_lua to
replace io.popen() and the alike. We'll still have to clone a new
child process anyway which is not C10K capable, but it will not block
the nginx workers at least. Patches welcome ;)
Best regards,
-agentzh