Personal finance on-demand
tl;dr Created a socket activated service to spin up a local webapp I use sometimes when something connects to it, and then tear it down again after 5 minutes
I’m a big personal finance nerd and have spent the last 3 years cultivating a ledger file that contains pretty much every facet of my financial life. This file is in a format understood by a suite of command line software called Beancount. It’s is made even better used in conjunction with Fava, a webapp to explore your beancount file.
Fava is a HTTP a service that reads your beancount file stored on disk and presents you with a series of reports and charts to help you make sense of it. I usually only use it when editing my file or occasionally when I need to check something.
For quite some time I had this as a
--user level systemd service, enabled to run on startup. This worked fine, but I noticed recently that the process seems to consume 2% CPU at all times. Not a big deal in the grand scheme of things but battery life on my laptop comes at a premium.
This made me think, what if there is a way of starting up Fava only when I need it 🤔, sort of like the serverless compute world where resources are spun up on-demand. It was at this point I remembered reading about systemd.socket where you can activate a service when something connects on a socket. At the time I’d filed it away under the “that sounds cool but I’ll probably never use it” place in my brain, but it’s pleasing to now have an actual use case!
The setup is as follows
fava.socket file under
~/.config/systemd/user - this sets up the socket.
[Unit] Description=Fava Socket PartOf=fava.service [Socket] ListenStream=127.0.0.1:5000 [Install] WantedBy=sockets.target
fava.service file under
~/.config/systemd/user - this defines the service
[Unit] Description=Fava After=network.target fava.socket [Service] Type=simple ExecStart=fava -H 127.0.0.1 /home/djh/beancount/financials.beancount RuntimeMaxSec=300 # kill the service after 5 minutes. [Install] WantedBy=default.target
Enable and start the socket + service
systemctl --user daemon-reload systemctl --user enable fava.socket systemctl --user start fava.socket
Go to a web browser and visit
http://127.0.0.1:5000 and Fava should load.
After 5 minutes the service will be terminated, but you can start it again by refreshing the page.
Ideally I’d want the socket to terminate the service if nothing connects to it for 5 minutes but I’m not sure how to do that, hence the
RuntimeMaxSec setting in the service file 😞
You might be wondering why not just host Fava on a Raspberry Pi, it’s a web application afterall. In my case I tend to only use it when editing my beancount file which is stored locally on my Mac. Changes are committed to a git repository when I’m happy with them. The hosted version could listen to changes to this git repository and keep its local copy up to date I suppose, but I’d have to constantly create/push commits to see my changes. This approach also requires network access.
Another way would to just run
fava directly on the command line when I need it, but I like the idea of requesting it on demand via a HTTP request and letting systemd handle the rest.
Anyways just thought I’d share x.