Using erlangs remote shell during devel.
Summary:
Have you ever worked on a project, you write enough code that you're looking at ways to reduce the time it takes to turn your idea into working, tested code. The ideas are many, but it feels like your wasted minutes add up so very quickly into an hour and the solutions start to boil in the back of your mind.
Ok, so you're writing tests and the tests prove the code is correct and work, so you find a quick way to run the 'eunit' tests in erlang itself, from a single chord.
Cool you think to yourself, thats quicker, but you remember the times you wrote lisp, and how quick the repl was, that you could make changes to the live project and see its behavior change in real time.
A spark burns in the back of your mind, you remember how rapidly you could develop on the common-lisp repl.. erlang has a repl, so why not see what we can do.
I wont be the first to talk about this, but I haven't seen anyone demonstrate a tight feedback loop from the editor into the erlang repl.
Introduction
Erlang is a distributed system out of the box and the erlang shell itself allows for a system to connect to any of the nodes in the distributed erlang system. The distribution itself demonstrated here is the non encrypted nono tls/ssl so probably not the best idea to do outside of development.
The ERTS documentation even suggests:
⚠ Warning:
Starting a distributed node without also specifying -proto_dist inet_tls will expose the node to attacks that may give the attacker complete access to the node and in extension the cluster.
If you dont secure this and do something better in production, something like my virus could end up using your code to laterally across different systems.
Firing up the emacs repl requires you to install erlang-mode and starting the erlang-shell with a few parameters.
You must setup emacs, this replaces the 'erlang-shell' with a remote erlang shell, that connects to the already running node.
Specifics:
The 'main' erlang program must be started before you can connect another "shell" to it. Lisp people may call this a 'networked repl', but in erlang parlance it is called a 'remote shell'. In this case both 'nodes' are on the same machine but there is nothing stopping you from doing this in a more distributed environment.
<stuff cut here here>
EXTRAS_EBIN = -pa ./_build/default/extras/examples/
export EXTRAS_EBIN
LIB_EBIN = -pa _build/default/lib/*/ebin
export LIB_EBIN
node1-noshell:
erl -sname node1 -setcookie mysecretcookie -noshell -noinput \
$(LIB_EBIN) $(EXTRAS_EBIN)
rebar3-shell
rebar3 shell --sname node1 --setcookie mysecretcookie
node1-noshell-yourapp:
erl -sname node1 -setcookie mysecretcookie -noshell -noinput \
$(LIB_EBIN) $(EXTRAS_EBIN) --eval "yourapp:start()"
You'd start the 'main' program with the command:
$ make node1-shell
or
$ make rebar-shell
Or if you're feeling lucky you can execute the command by line, the goal is to ensuret hat you have the nodename configured to node1.
Modify your emacs, to evaluate this code,
(defun remote-erlang-shell ()
"Starts an inferior Erlang shell with a randomized -sname using a random string."
(interactive)
(let* (
(chars "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
(len 5) ; Length of the random part (e.g., 5 characters)
(random-part (with-temp-buffer
(dotimes (i len)
(insert (aref chars (random (length chars)))))
(buffer-string)))
(random-name (concat "node-" random-part))
(command (format "erl -sname %s -setcookie mysecretcookie -remsh node1" random-name)))
(inferior-erlang command)))
Each node in the 'cluster' must have a unique name, this lisp code creates a random name for the local connection and connects to the remote node.
Now when executing m-x remote-erlang-shell , within emacs it should try to connect to the 'remote node' (in this case whatever node1 is running).
If the runtime tells you it can't find node1, check to Section 9.8 - Why won't my distributed Erlang nodes communicate?.
Now when you compile an erlang file, (C-c C-k or erlang-compile) it should compile (and be loadable) in the same remote node.
If the code compiles to a location where the BEAM vm will find it, the next time the code runs through a function in the module, the vm should pick up and use the new function.
This allows you to do do 'live' repl updates to the running application, see the demo here when i'm working on an early version of cellium.
It is not strictly limited to 'compiling' code, you can also write erlang functions that you would run at the repl, and I've always wanted to say this, I leave it as an exercise to the reader.
Conclusion
This workflow is super convenienct; it fundamentally changes the nature of the interaction with the system. By adopting the remote shell workflow, you are no longer treating your application as a fragile, compiled artifact that must be stopped and restarted after every minor change. Instead, you're embracing the true power of Erlang/OTP: live, continuous development and maintenance.
This is the very essence of "operational elegance" in Erlang. It doesn't just "let it crash"; it *allows you to fix problems in the live system.
The ability to connect, inspect, and update code in-situ is a critical advantage for building highly available, fault-tolerant systems* that truly never have to go down. Stop the cycle of restarts and start developing your Erlang application the way it was designed to be run: alive.
Resources:
Erlang/OTP Documentation (The Core)
Code Loading Mechanism (Hot Code Swapping): A deep-dive explanation of "Code Replacement" and the "Current" and "Old" module versions.
Erlang/OTP Documentation: Compilation and Code Loading
The Erlang Command (`erl`): Reference for all the crucial flags used to start a distributed node, including `-sname`, `-setcookie`, and `-remsh`.
Community Tutorials and Guides
Learn You Some Erlang for Great Good
An accessible community resource with excellent, practical sections covering the shell, distribution, and general Erlang philosophy.
The Erlang Shell in Depth: Detailed reference for the commands available inside the Erlang shell, such as `c(Module)` and job control (`^G`).
Emacs/LISP Integration Specifics
Official Erlang Mode for Emacs: The core documentation for `erlang.el`, which provides the foundation for commands like `erlang-shell` and `erlang-compile`.
Blog Post: Connect to remote erlang shell while inside emacs
How to connect to a remote shell in emacs (but a little.. different)
Section 9.8 - Why won't my distributed Erlang nodes communicate?