2

What's the best way to do OS process management from Erlang? I need to be able to spawn child OS processes, write to the child's stdin, read from both stdout and stderr, send kill signals, and get notified of exit codes. I don't see that this is possible with what's in erts.

I know about erlexec, but I don't know if it's stable or if anyone is actually using it in anger. Are there any other options, or is that the best?

regularfry
  • 3,248
  • 2
  • 21
  • 27

2 Answers2

3

Port programs are the best way to do this. Port programs are safe and won't harm the Erlang VM, and if they crash or mis-behave can be killed and restarted like any other Erlang process.

Port Drivers are different and if they mis-behave can bring down the entire Erlang VM.

  • Ok. erlexec is a port program designed for running arbitrary child processes, so it looks at least like the right approach. It's a little weird that nobody else seems to have used it, though - is it really that uncommon a requirement? – regularfry Apr 27 '11 at 11:40
  • Writing Port wrapper programs in just about any reasonable language is very simple, C and Python both have libraries for converting terms to binaries and back again to language native structures. `erlexec` is a general purpose wrapper program for any arbitrary executable. If you want specific behavior, and most people do, they write their own Port wrapper program. I usually use Python since they are small proxy programs with little logic and performance of the serialization and deserialization isn't usually and issue. –  Apr 27 '11 at 15:07
2

In Erlang standard way to manage OS processes is ports.

Exit status of spawned OS process will be sent as a message if option exit_status added to open_port:

1> P = open_port({spawn, "/bin/ls unknown_file_name"}, [exit_status]).
#Port<0.486>
/bin/ls: cannot access unknown_file_name: No such file or directory
2> flush().
Shell got {#Port<0.486>,{exit_status,2}}
ok

Data can be written to stdin of spawned OS process by sending a message to port or by port_command function and stdout content will be sent as a message. (Note also {line, L} and {packet, N} options of open_port):

1> P = open_port({spawn, "/bin/cat"}, [stream, binary]).
#Port<0.486>
2> true = port_command(P, <<"data">>).
true
3> flush().
Shell got {#Port<0.486>,{data,<<"data">>}}
ok
4> true = port_close(P).
true

Stderr also can be redirected to stdout:

1> P = open_port({spawn, "/bin/ls unknown_file_name"}, [stderr_to_stdout, binary]).
#Port<0.486>
2> flush().
Shell got {#Port<0.486>,
    {data,<<"/bin/ls: cannot access unknown_file_name: No such file or directory\n">>}}
ok

However you can't send kill signals with ports but if you close port by sending a message to port or by calling port_close external process can exit by SIGPIPE signal.

hdima
  • 3,627
  • 1
  • 19
  • 19