akash-akya
ExCmd - communicate with external programs with back pressure
Hi all,
I’m tinkering around the idea of streaming data through an external program (think streaming video through ffmpeg command and receiving the output back) from the last few weeks. Mainly focused on communicating with long-running programs with back-pressure. After exploring many approaches I settled on this. ExCmd uses named FIFO to solve back-pressure and other issues. It also uses odu (which is based on goon) to fill gaps in the erlang ports.
Currently, it’s at an early stage. I’m still thinking about the interface it should provide to expose all its functionality for different use cases effectively.
Please check it out and share your feedback ![]()
Background
Why not use built-in ports?
- Unlike beam ports, ExCmd puts back pressure on the external program
- Proper program termination. No more zombie process
- Ability to close stdin and wait for output (with ports one can not selectively close stdin)
While exploring the options, I also played around another approach, which does not use named FIFO. Its more like GenStage, the receiver beam process “demands” external program for output using stdin and stdout., but it has its own set of other issues.
Most Liked
akash-akya
Added ability to stream input and output. Now one can do something like this
def audio_stream!(stream) do
# read from stdin and write to stdout
proc_stream = ExCmd.stream!("ffmpeg", ~w(-i - -f mp3 -))
Task.async(fn ->
Stream.into(stream, proc_stream)
|> Stream.run()
end)
proc_stream
end
File.stream!("music_video.mkv", [], 65535)
|> audio_stream!()
|> Stream.into(File.stream!("music.mp3"))
|> Stream.run()
Along with this there are many changes related to interface and error handling. Please check documentation for more details
v0.1.0
Github
akash-akya
v0.3.0
This is a major release with completely different approach to solve the back-pressure. Ditched named pipes in favor of slightly complicated protocol. And with that ExCmd no longer has scheduler issuers.
I did consider this approach before, but dropped after I hit a blocker. Thanks to @ananthakumaran for clearing it up ![]()
Changes
- fixed beam scheduler issues
- demand-driven protocol for back-pressure instead of named pipes
- few breaking changes to options
- many internal changes for maintainability. Such as,
ExCmd.Processnow usesGenSteteMachineinstead ofGenServer
akash-akya
The main issue which ExCmd tries to solve, which none of these libraries solve is having proper stream with back-pressure. In these libraries progress of the external command is uncontrolled.
Internally they all use the port and some sort middleware program for IO. We can never have back-pressure (or limit) using ports as the process mailbox is unbounded. ExCmd also uses port and a middleware program (odu) but it only uses port for controlling the external program not for IO. For IO it uses named pipe (FIFO) which is demand-driven.
One can just write the output to a file and read that from to “solve” this. But,
- This involves disk IO for writing and reading which add latency
- We can not control external program speed
- we have to cleanup these files properly which might not be trivial
- and IMHO ergonomics is better with ExCmd approach as the stream is more composable
Apart from these issues,
erlexec: It is more focused on orchestrating and linking the external command than on communicating with it. If erlexec accepts os pid for its functionality maybe we can use erlexec with ExCmdporcelain: There are few important issues like zombie process and not having the ability to forcefully killrambo: similar to porcelain, but rambo does not allow streaming input to stdin so all input must be kept in memory or it has to be passed to the command by writing to a file. It collects output binary in memory by appending it which is not efficient
I think when these libraries were created, they were not trying to solve the issues I mentioned, so I think its not correct to compare them. Please let me if anything is incorrect.
Popular in Announcing
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









