2e3s / awatcher

Activity and idle watchers
Mozilla Public License 2.0
146 stars 5 forks source link

Add systemd service #23

Closed wojnilowicz closed 4 months ago

2e3s commented 5 months ago

Thank you for your suggestion, doesn't ActivityWatch manage the modules and run the modules itself? I have added a similar functionality myself to the bundled version which works almost identically to the original distribution of ActivityWatch (particularly, Qt-based tray icon app).

Or is it about the delays? If some environment requires a timeout, I think it may be considered in the code to facilitate the usage for everyone, for example, I added delays and more attempts for #8 and #11

wojnilowicz commented 5 months ago

You're welcome. Indeed, this is a suggestion. I use it.

ActivityWatch manages its modules, if you run them through aw-qt. It also has a systemd service at https://github.com/ActivityWatch/aw-server-rust/blob/82345cfc5371c673a9bc2b5284530ae8c180153d/aw-server.service that lets you start aw-server, but then its modules don't start. This MR is for aw-awatcher to start just like aw-server. No need to start aw-qt.

The issue with delay is so that if aw-server doesn't initialize fully then aw-awatcher goes dead, but systemd doesn't know that. If you can fix that somehow (either by failing aw-awatcher or idling for aw-server) then it would be even a better solution.

BTW, I believe the issues you pointed doesn't help me. I don't use bundled version and I use you latest watcher and still have to be careful when to start your watcher.

2e3s commented 5 months ago

The issue with delay is so that if aw-server doesn't initialize fully then aw-awatcher goes dead, but systemd doesn't know that.

There are 3 reconnection attempts with 1 second interval, doesn't this work for you? Maybe, 3 attempts/2 seconds waiting is not enough? It has After=aw-server.service, so I would expect it to work, especially after the delay.

either by failing aw-awatcher

Doesn't aw-awatcher fail the way which is recognized by systemd?

wojnilowicz commented 5 months ago

The issue with delay is so that if aw-server doesn't initialize fully then aw-awatcher goes dead, but systemd doesn't know that.

There are 3 reconnection attempts with 1 second interval, doesn't this work for you? Maybe, 3 attempts/2 seconds waiting is not enough?

Certainly not on my old machine. It's far too less. I also have a newer and quite fast machine, but I wouldn't bet that 3 times 1 s is enough for it 🙂

It has After=aw-server.service, so I would expect it to work, especially after the delay.

After=aw-server.service is not helpful here as it only marks that the aw-server executable has been launched. I believe your awatcher expects to communicate with it to not fail, and for this aw-server needs a bit more time, hence the delay of 100 seconds. My newer machine can go way below these 100 seconds, so this solution is not perfect, so you could come up with something more robust if you want to invest time in it.

either by failing aw-awatcher

Doesn't aw-awatcher fail the way which is recognized by systemd?

I'm not an expert on this but replacing the delay with

Restart=on-failure
RestartSec=30

under the service tag doesn't help, so I concluded that it doesn't actually report failing. Maybe the return code is still zero.

2e3s commented 5 months ago

under the service tag doesn't help, so I concluded that it doesn't actually report failing. Maybe the return code is still zero.

Just checked, the return code is ok if you have this error:

Error: Failed to create bucket aw-watcher-afk_demi-desktop-linux

Caused by:
    0: error sending request for url (http://127.0.0.1:5600//api/0/buckets/aw-watcher-afk_demi-desktop-linux): error trying to connect: tcp connect error: Connection refused (os error 111)
    1: error trying to connect: tcp connect error: Connection refused (os error 111)
    2: tcp connect error: Connection refused (os error 111)
    3: Connection refused (os error 111)
$ echo $?
1
wojnilowicz commented 5 months ago

Yes, maybe I should experiment a bit more with this. Thanks for the error codes listing. I'm surprised that an error code could be 0. Shouldn't that be reserved for "everything's ok"?

2e3s commented 5 months ago

I'm surprised that an error code could be 0. Shouldn't that be reserved for "everything's ok"?

I'm not sure I understand, the error code for awatcher is 1 when the aforementioned exception happens as echo $? shows in the snippet. Otherwise, 0 is returned on a regular exit, I've just checked.

wojnilowicz commented 5 months ago

Ok, I did no try it yet, so maybe I don't quite understand what "0: error sending request for url [...]" means.

luisgerhorst commented 5 months ago

Here's what I'm using:

[Unit]
Requires=aw-server.service
After=aw-server.service

[Service]
Type=simple
# Verbosity level: -v for warnings, -vv for info, -vvv for debug, -vvvv for trace
ExecStart=/bin/bash -c 'aw-awatcher --version && aw-awatcher -vvvv'
Restart=always
RestartSec=60
Nice=18
IOSchedulingPriority=6
# Was not able to test this on a system where it has an effect:
# CPUQuota=10%

[Install]
WantedBy=default.target

and

[Unit]
After=network.target

[Service]
Type=simple
ExecStart=/bin/bash -c 'aw-server'
Restart=on-failure
RestartSec=60
Nice=18
IOSchedulingPriority=6
# Was not able to test this on a system where it has an effect:
# CPUQuota=10%

[Install]
WantedBy=default.target

Not sure, but maybe setting Nice would be something to consider?

wojnilowicz commented 5 months ago

Thanks for sharing, but I'm not sure "nice" is a robust solution here.

Now I'm just leaning more toward that this should be fixed on ActivityWatch side through something called forking as seen at https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html which will assure that aw-server is initialized fully before aw-aw_watcher starts.

Then here the systemd service could be minimal.

wojnilowicz commented 4 months ago

I used sd-notify in aw-server-rust to inform systemd exactly when the server is up and running and only then start awatcher, but that didn't help during boot, so it's not about non-existent communication with aw-server-rust.

What I found is that without ExecStartPre=/bin/sleep 100 awatcher starts and immediately exits successfully. I suspect that in my case it's because kwin_x11 is not yet initialized. ExecStartPre=/bin/sleep 100 adds enough time for it to start. That's not robust, because the time it has to wait depends on the machine it runs.

The new version of the service should be robust on every system. It sleeps for 5 seconds after aw-server.service or graphical-session.target (that's where kwin_x11 starts) starts. If it will not find KDE or GNOME, it'll exit successfully, but will try to restart itself after 5 s then after 10 s and then after every 15 s and will finally give up after 2 minutes.

Could you accept that PR?

2e3s commented 4 months ago

Thank you for your updated config. It looks more robust and shareable, but it requires aw-server.service too. I've merged it anyway (to another folder, "watcher" is a local crate), and mentioned it in readme.