shellac
shellac is a suite of software which aims to provides OS-level
process control for the Elixir language. The software is composed of two
sub-projects which coordinate to accomplish this goal:
lacca: an Elixir process control library, implemented as an OTP application which can be included in amixproject.resin: a Rust binary which acts as a companion to thelaccaOTP application. This binary provides process control and supervision, it also multiplexes the process's open file descriptors onto the single BEAM port.
Build Instructions
You will need an Elixir toolchain (mix) and a Rust toolchain (cargo) to
properly build this project. From the project directory run the following
commands:
mix deps.get-- download dependenciesmix deps.compile-- compile dependencesmix compile-- compileslaccato the_build/directory.NOTE: the compile step will run
cargo buildon theresin/directory. The artifacts from this build will be placed inpriv/resin/which must be deployed with thelaccaOTP application.
Since this project builds native code (a Rust executable), you will need to
build this OTP application / release on the target platform. If you need to
change how the resind executable is built you can modify the Makefile
in this project directory.
Protocol Versioning
The lacca and resin programs do not follow standard semantic versioning
guideliens. Please read the following to understand how the project's versions
are controlled. The developer's suggest pinning both a major AND minor version
when using build tools which expect semantic versioning. i.e: pin to
"\~> 1.3.0" rather than "\~> 1.3" in your build tool. This would allow the patch
version to change, but not the major or minor version.
The version number consits of protocol, library, and patch components.
Their significance to the project is as follows:
protocolwill whenever the protocol betweenlaccaandresinare changed in non-backwards compatible ways. Newer major versions ofresinwill work with older versions oflacca, but not vice versa.minorwill be changed to reflect breaking changes to the program's API.Such changes for
laccamight include:- Removed functions
- Change of non-optional arguments to a function
- Change in return value from a function
Such changes to
resinmight include:- Command line options renamed or removed
- Change in interpretation of command line arguments
patchwill be changed when backwards-compatible changes are introduced to either the protocol, library, or daemon.
NOTE: v0 of the protocol is considered unstable. For best results
you should always build and deploy the v0 programs together.
Protocol Format
shellac v0 packets are sent on the wire as follows:
- (n) two bytes identifying packet length
- (data) packet specific data (n bytes, CBOR encoded)
Packet Types
Packet types are as follows:
TBD
- Start Process (exec: string, args: [string]])
- Stop Process ()
- DataOut (ty: (Stdout | Stderr), buf: [u8])
- DataIn (buf: [u8])
Future Additions
- POSIX signal support?
- windows support?
- Standard stream redirection?
- Buffered input mode?
Lacca Design
When the lacca application starts it will kick off a supervision
process. To start an OS-level process lacca will perform the
following initialization sequence:
Start a child BEAM process w/ the given command line.
Open a port to a
resindaemon in:binarymode.Handshake w/ the
resindaemon to verify matching protocol versions.Pass the initialization arguments to the
resindaemon.Enter a message loop awaiting messages from the port, as well as messages from other peers in the Erlang VM.
TODO
resin: general clean up of error handling
- what to do with errors if stdout goes away?
- logging facilities?
resin: signal handling architecture
-
need more generalized support for sending processes different kinds of
signals, not just calling
Child::kill() - wtf do we do on Windows land?
-
need more generalized support for sending processes different kinds of
signals, not just calling
resin: restructure as state machine?
- there are bits of the server process state which don't exist until the inferior process is running. it would be nice if this was encoded in the type system as some kind of FSM so I can stop unwrapping Option<..> everywhere.
resin: multi proc support
-
Should one daemon be able to handle multiple inferior processes?
I think this is what
erlexecdoes but I'm not sure.
-
Should one daemon be able to handle multiple inferior processes?
I think this is what
lacca: explore stdout/stderr space
- with streams how do we signal EOF?
- what if user wants to stream by line?
-
should we send messages to interested processes instead of a
buffer that is read-once? (
flush()destroys the contents of the buffer...)
packaging (hex.pm): how do we distribute both halves effectively? distribute source and call
cargofrom Mix?