Moving Atuin to a daemon

I finally have a very unstable version of this running on my laptop :partying_face:

Still needs a bunch of work, but right now it works something like this

  1. Run atuin daemon somewhere. Leave it running
  2. daemon.enable = true in config
  3. Just use Atuin and it’ll send history over a unix socket, instead of writing sqlite directly.

SQLite is still read directly for the TUI, but the main goal here is to get disk access off of the hot path. Once that’s done, it can start to be used for some of the other things we discussed :raised_hands:

4 Likes

For NixOS a systemd service is the easiest and for that we just need to run atuin daemon and we don’t need any extra daemonizing logic.

We don’t backport updates usually, so only nixpkgs unstable is representive.

1 Like

and anything before 23.11 is EoL regardless

1 Like

This works pretty well for me so far!

PR:

I’ll merge soon it as it seems usable, but it will still need a bunch more testing as I’m sure there are cases where it doesn’t work so well

If anyone fancies trying it, add

[daemon]
enabled = true
socket_path = "/some/path/to/where/you/want/the/unix/socket"

and run atuin daemon somewhere

It will

  1. Bind the unix socket, and start a grpc service
  2. Maintain a map of “in progress” commands in memory, rather than in sqlite
  3. Stop writing to the database while you’re using the terminal
  4. Run a regularly scheduled background sync, by default every 5m but configurable with daemon.sync_frequency, in seconds

I might be able to port the daemon to windows, it might need a separate script to run at startup to start the daemon thought (but that shouldn’t be a problem hopefully!)

1 Like

That would be great, thank you!

What would the script be needed for, it cannot be ran manually in the foreground? (for now)

It would be to start the service up when the system starts up, i havent looked into it too much though

What is the proper way to start the atuin daemon on macOS? A launchctl service?

@YummyOreo / @tessus That would be good, but please avoid it for now - the current implementation doesn’t include any such scripts, as it’s intended only for testing. I’d rather nobody use it seriously just yet.

Just run atuin daemon in the foreground somewhere for the time being

There’s also a whole bunch of discussion in this thread concerning the best way to start and run the daemon, but yes launchctl is an option for macos.

I’d like to put the socket file at $XDG_RUNTIME_DIR/atuin.sock. Could this be supported in some way? (i.e. use the same config file but works on different machines with different $XDG_RUNTIME_DIR.)

It’s not supported currently, and I suppose we’d need to allow env vars in filepaths in config

Have you seen how Roman Perepelitsa handles git status via gitstatusd in powerlevel10k?

It’s a small daemon, that is downloaded and forked automatically without any user interaction.

I especially like that it doesn’t need any kind of systemd/launchctl etc. and just works.

The “downloaded” part makes me very worried.

Forking on its own doesn’t seem good for me. Its stdout / stderr is lost (though you could redirect it elsewhere early). It can be killed because the session is over, or it won’t exit and some other process waits for it to finish (e.g. ssh).

A systemd.socket unit will be good to start it automatically without user interaction (like PulseAudio / PipeWire).

I’ve used the daemon for some days. It works pretty well, except when it is restarted. Not only the restart command is lost, but also all started but unfinished commands in other terminals too. Maybe the daemon could save the unfinished commands before exiting?

We wouldn’t have to download anything, that’s just how powerlevel10k does it with gitstatusd.

The daemon part could just be part of the regular atuin binary.

Communication with the daemon could happen via a private socket, and if no daemon is running, atuin could just spawn it and then have it run forever in the background or exit after a period of no activity.

It may not. And it may exit without a clue why it has exited (I have an auto-spawn daemon which exits randomly without any trace.)

It takes time. systemd user session does have this idea to close a session after a period of no activity, but nobody is going to wait for the session to close.

I think this would be the ideal approach: Moving Atuin to a daemon - #7 by ellie

Yep definitely an issue atm, in-progress commands are just in memory. I think dumping them to some temp file would work, I’d rather avoid committing incomplete data to the database. I know that’s how the old implementation worked, but it was quite impure + had issues.

It already is!

Yep it uses a unix socket, or TCP on not-unix. See: Moving Atuin to a daemon - #24 by ellie

I didn’t know about gitstatusd though. Seems neat!

Totally agree, but I would almost always opt for option #2.
And if option #2 is robust, then I don’t see much need for option #1.

For context, I’ve setup the daemon as follows on Ubuntu 22.04:

  1. Create ~/.config/systemd/user/atuin-daemon.service which contains:
[Unit]
Description=Background Daemon Unit for Atuin-Daemon

[Service]
Type=simple
ExecStart=/home/<myuser>/.atuin/bin/atuin daemon

[Install]
WantedBy=default.target
  1. Updated ~/.config/atuin/config.toml and added the following lines:
[sync]
records = true
# Daemon mode requires sync v2

[daemon]
enabled = true
socket_path = "/run/user/1000/atuin.sock"
# Note the above path assumes UID 1000
  1. Run systemctl enable --now --user atuin-daemon.service

Let’s see how this goes!

3 Likes

While I have seen people reference a userid for a socket, I was also wondering whether the socket isn’t or couldn’t be user agnostic.

Can I setup one daemon/socket and multiple users use this one socket? It’s not that far fetched, since the client has the user/key info.

Anyway, just thinking out loud.

Edit: So, if I run atuin on a Linux machine and there are 20 users, 20 daemons have to be running?