All Projects → akash-akya → exile

akash-akya / exile

Licence: Apache-2.0 license
Alternative to ports for running external programs. It provides back-pressure, non-blocking io, and solves port related issues

Programming Languages

elixir
2628 projects
c
50402 projects - #5 most used programming language

Projects that are alternatives of or similar to exile

Byte Stream
A non-blocking stream abstraction for PHP based on Amp.
Stars: ✭ 208 (+181.08%)
Mutual labels:  stream, non-blocking
react-webrtc-chat
React WebRTC chat
Stars: ✭ 39 (-47.3%)
Mutual labels:  stream
binary
Clojure API for binary format I/O using java's stream apis
Stars: ✭ 67 (-9.46%)
Mutual labels:  stream
live-stream-media-source-extensions
Live stream h264 encoded mp4 video on media source extensions using ffmpeg, node.js, socket.io, and express. Works in chrome, firefox, safari, and android. Not iOS compatible. Work has moved to mse-live-player repo =>
Stars: ✭ 24 (-67.57%)
Mutual labels:  stream
net-Socket
A minimalist wrapper around System.Net.Sockets.Socket.
Stars: ✭ 21 (-71.62%)
Mutual labels:  stream
fridgefm-radio-core
Simple lightweight package for creating your own radio station via NodeJS heavily inspired by Shoutcast and Icecast.
Stars: ✭ 32 (-56.76%)
Mutual labels:  stream
wasm-streams
Bridging between web streams and Rust streams using WebAssembly
Stars: ✭ 61 (-17.57%)
Mutual labels:  stream
cassandra4io
Asynchronous lightweight fs2 and cats.effect.IO wrapper under datastax cassandra 4.x driver with doobie-like syntax
Stars: ✭ 40 (-45.95%)
Mutual labels:  non-blocking
arxwasm
Port of Arx Libertatis to WebAssembly using Emscripten
Stars: ✭ 28 (-62.16%)
Mutual labels:  port
multipart-read-stream
Read a multipart stream over HTTP
Stars: ✭ 13 (-82.43%)
Mutual labels:  stream
deep-action-detection
Multi-stream CNN architectures for action detection with actor-centric filtering
Stars: ✭ 24 (-67.57%)
Mutual labels:  stream
RxIo
Asynchronous non-blocking File Reader and Writer library for Java
Stars: ✭ 20 (-72.97%)
Mutual labels:  non-blocking
wise-river
Object streaming the way it should be.
Stars: ✭ 33 (-55.41%)
Mutual labels:  stream
RxLoading
RxJava library for showing a loading (i.e. progress bar) state while waiting for async data with minimal effort and advanced options.
Stars: ✭ 49 (-33.78%)
Mutual labels:  stream
node-stream-equal
Test that two readable streams are equal to each other.
Stars: ✭ 24 (-67.57%)
Mutual labels:  stream
go-callbag
golang implementation of Callbag
Stars: ✭ 19 (-74.32%)
Mutual labels:  stream
live-torrent-backend
The backend server for the live-torrent project
Stars: ✭ 38 (-48.65%)
Mutual labels:  stream
rxjava2-http
Transmit RxJava2 Flowable over http with non-blocking backpressure
Stars: ✭ 19 (-74.32%)
Mutual labels:  stream
node-jstream
Continuously reads in JSON and outputs Javascript objects.
Stars: ✭ 13 (-82.43%)
Mutual labels:  stream
knockonports
A port knocking client for Android
Stars: ✭ 25 (-66.22%)
Mutual labels:  port

Exile

Exile is an alternative to ports for running external programs. It provides back-pressure, non-blocking io, and tries to fix ports issues.

Exile is built around the idea of having demand-driven, asynchronous interaction with external process. Think of streaming a video through ffmpeg to serve a web request. Exile internally uses NIF. See Rationale for details. It also provides stream abstraction for interacting with an external program. For example, getting audio out of a stream is as simple as

Exile.stream!(~w(ffmpeg -i pipe:0 -f mp3 pipe:1), input: File.stream!("music_video.mkv", [], 65535))
|> Stream.into(File.stream!("music.mp3"))
|> Stream.run()

See Exile.stream!/2 module doc for more details about handling stderr and other options.

Exile.stream!/2 is a convenience wrapper around Exile.Process. Prefer using Exile.stream! over using Exile.Process directly.

Exile requires OTP v22.1 and above.

Exile is experimental and it is still work-in-progress. Exile is based on NIF, please know the implications of it before using it

Rationale

Existing approaches

Port

Port is the default way of executing external commands. This is okay when you have control over the external program's implementation and the interaction is minimal. Port has several important issues.

  • it can end up creating zombie process
  • cannot selectively close stdin. This is required when the external programs act on EOF from stdin
  • it sends command output as a message to the beam process. This does not put back pressure on the external program and leads exhausting VM memory

Middleware based solutions

Libraries such as Porcelain, Erlexec, Rambo, etc. solves the first two issues associated with ports - zombie process and selectively closing STDIN. But not the third issue - having back-pressure. At a high level, these libraries solve port issues by spawning an external middleware program which in turn spawns the program we want to run. Internally uses port for reading the output and writing input. Note that these libraries are solving a different subset of issues and have different functionality, please check the relevant project page for details.

  • no back-pressure
  • additional os process (middleware) for every execution of your program
  • in few cases such as porcelain user has to install this external program explicitly
  • might not be suitable when the program requires constant communication between beam process and external program

On the plus side, unlike Exile, bugs in the implementation does not bring down whole beam VM.

ExCmd

This is my other stab at solving back pressure on the external program issue. It implements a demand-driven protocol using odu to solve this. Since ExCmd is also a port based solution, concerns previously mentioned applies to ExCmd too.

Exile

Internally Exile uses non-blocking asynchronous system calls to interact with the external process. It does not use port's message based communication instead does raw stdio using NIF. Uses asynchronous system calls for IO. Most of the system calls are non-blocking, so it should not block the beam schedulers. Makes use of dirty-schedulers for IO.

Highlights

  • Back pressure
  • no middleware program
    • no additional os process. No performance/resource cost
    • no need to install any external command
  • tries to handle zombie process by attempting to clean up external process. But as there is no middleware involved with exile, so it is still possible to endup with zombie process if program misbehave.
  • stream abstraction
  • selectively consume stdout and stderr streams

If you are running executing huge number of external programs concurrently (more than few hundred) you might have to increase open file descriptors limit (ulimit -n)

Non-blocking io can be used for other interesting things. Such as reading named pipe (FIFO) files. Exile.stream!(~w(cat data.pipe)) does not block schedulers, so you can open hundreds of fifo files unlike default file based io.

TODO

  • add benchmarks results

🚨 Obligatory NIF warning

As with any NIF based solution, bugs or issues in Exile implementation can bring down the beam VM. But NIF implementation is comparatively small and mostly uses POSIX system calls. Also, spawned external processes are still completely isolated at OS level.

If all you want is to run a command with no communication, then just sticking with System.cmd is a better option.

License

Copyright (c) 2020 Akash Hiremath.

Exile source code is released under Apache License 2.0. Check LICENSE for more information.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].