Launching Dev Dependencies with tmux
When working on CollBox, we have a handful of external services
the app depends on which we need to have running at development time.
I used to run these via Foreman, but somewhere along the way my
Ruby installation seems to have gotten borked (thanks, Catalina?)
and since then I’ve been running the services by hand. I always work
in a tmux
session anyway, so I decided it was time to see
what it would look like to launch my window full of dependencies in
tmux
from a script.
As it turns out, tmux
is fantastically scriptable. If you simply
run tmux <command>
from a shell inside of a tmux
session, that
command will be run by the encapsulating tmux
instance, and these
are the same set of commands that can be bound to your tmux
keyboard
shortcuts. You can also simply send a stream of keystrokes to panes
inside of tmux
. All of this means running my four dependencies in a
single window (named “deps”) under their own panes is as simple as:
#!/bin/sh
# deps.sh
tmux new-window -n "deps"
tmux send-keys "redis-server redis.conf" Enter
tmux split-window
tmux send-keys "datomic/bin/transactor transactor.properties" Enter
tmux split-window
tmux send-keys "lein shadow-watch" Enter
tmux split-window
tmux send-keys "npx gulp" Enter
tmux select-layout tiled
When I’m ready to work on the project I simply run ./deps.sh
at my
shell and I end up with something like this:
+---------------------------------+---------------------------------+
| $ redis-server redis.conf | $ datomic/bin/transactor transa |
| ... | ... |
| | |
| | |
| | |
| | |
| | |
|---------------------------------+---------------------------------|
| $ lein shadow-watch | $ npx gulp |
| ... | ... |
| | |
| | |
| | |
| | |
| | |
+---------------------------------+---------------------------------+
| 1:deps* | 2:zsh | |
+-------------------------------------------------------------------+
fin.
A few thoughts on other tools that can be used to address this same problem:
- Foreman: Great project; I’ve used it happily for years. I love
the aggregated, colorized logs, which keep things compact yet
comprehensible. The one downside is that it’s not convenient to
restart a single service, should you need to. But my main reason
for switching was just to see if I could avoid the additional
dependencies to my development stack given that I already use
tmux
. - tmuxinator: Looks like a nice project to encapsulate essentially what I did above into a simple data-driven format, but I don’t see that the gains are big enough (at least for my simple case) to bother adding the additional dependencies.
- Docker: As much as I like the idea of cleanly locking down development dependencies in the Docker style, in practice I’ve found it exceptionally costly, both in terms of the performance overhead (I literally had to buy a new laptop at my last job once we switched to Docker), and the increased complexity of accessing application state / debugging.