Using systemd to keep a RSS feed reader up-to-date

In my last post I talked about how I use Elisp to programmatically organise and prioritise my news reading.

In this post I’ll talk about how I use a number of different functionalities provided by systemd — such as running services, running one-off commands, and scheduling jobs — to keep my news feed reader (elfeed) up-to-date.

A news feed reader service (daemon)

I begin by creating a systemd service that launches an emacs instance in daemon mode. This instance will run elfeed and will be solely responsible for managing all my news. I’m able to attach to this emacs daemon instance from both my graphical desktop, and a terminal (which I can reach remotely via SSH). [1]

The file ~/.config/systemd/user/emacs-elfeed.service is as follows:

[Unit]
Description=Emacs elfeed RSS reader daemon

[Service]
Type=forking
ExecStart=/usr/bin/emacs --daemon=rss

[Install]
WantedBy=default.target

Updating the news feed reader

Given that the emacs news feed reader instance is now running, I create a “one shot” command that connects to above emacs instance, and updates my news feeds. This is achieved by creating a systemd service of type oneshot.

The file ~/.config/systemd/user/emacs-elfeed-update.service is as follows:

[Unit]
Description=Update RSS feeds in emacs elfeed RSS reader
Requires=emacs-elfeed
Wants=emacs-elfeed-update.timer

[Service]
Type=oneshot
ExecStart=emacsclient --socket-name=rss -e '(progn (elfeed-update) (elfeed-apply-hooks-now))'

[Install]
WantedBy=default.target

Scheduling updates of the news feed reader

Finally, I want to update the news feed periodically. I do this using systemd timers . I create a timer to run every 15 minutes. The timer will run the one-shot service of the same name (“emacs-elfeed-update”). Note, that in this case, it is the one shot service that wants the timer, and not the other way around.

The file ~/.config/systemd/user/emacs-elfeed-update.timer is as follows:

[Unit]
Description=Run update on RSS feeds in emacs elfeed once every 15 minutes

[Timer]
OnCalendar=*:0/15

[Install]
WantedBy=timers.target

Conclusion

As a system, the above works like so:

    • The emacs news feed reader daemon runs on startup
    • Every 15 minutes, the timer runs the one-shot service
    • The one-shot service connects (if possible) to the emacs news feed reader daemon and runs an update command

While the above functionality could be implemented using shell scripts and cronjobs, I found that the solution could be expressed simply using systemd.

Footnotes

[1] I attach to an emacs news feed reader instance instead of starting new instances, because it helps to avoid synchronisation issues which can arise when multiple news feed reader instances are running.