Procd_add_reload_trigger only sometimes works

Hello everyone,
So I am working on adding some custom init.d scripts and uci config files to my OpenWRT 19.07.8 system. However, I am running into a problem where sometimes running reload_config doesn't actually trigger the /etc/init.d/... reload. Sometimes it will work, sometimes it won't. It seems to be random and more or less a 50/50 chance.

My init.d script is super simple, doesn't even spawn any instances:

#!/bin/sh /etc/rc.common
USE_PROCD=1
start_service() {
             /opt/screend start
}
stop_service() {
             /opt/screend stop
}
reload_service() {
             /opt/screend reload
}

service_triggers() {
        procd_add_reload_trigger screend
}

Running the following:

uci set screend.something=something_random
uci commit
reload_config

sometimes causes the reload_service function to be called, and sometimes it doesn't. I was able to confirm this by adding logger calls to the reload_service function. Does anyone know what could be happening here? Running ubus monitor always shows the event triggering, and it seems procd doesn't always hear it.

It feels that you may be nailing it right there. if there isn't an instance managed by procd, I'd say procd doesn't have any instance to call reload on.

You should be able to see running instances with something like:

ubus call service list '{"name":"screend","verbose": true}'

That init script is NOT using procd functionality, you should remove USE_PROCD=1 and follow the instructions here to write the correct syntax for "normal" init scripts

If you actually want to use procd in your init script you need to use a lot of special procd_something_something options to configure procd to start, monitor and manage the service, as written in these instructions

You can't just write raw console commands like /opt/screend start in a procd init script. That will not configure procd to track your process correctly

I understand that procd is usually used with instances. However, to the best of my knowledge, I don't see see a reason why that should be necessary to run the triggers. Running PROCD_DEBUG=1 to me at least implies that the behavior of the trigger has nothing to do with the instances that are running (and it infact implies the reloads of the init.d script itself). One would logically conclude that since procd can run with multiple instances, and a init.d can start multiple instances based off of the number of options in a config, one could configure an empty config and end up with zero instances. Either I'm missing something, or that's a big limitation of procd. For example, the autossh package with an empty config would lead to this situation. Also, I based my script off of /etc/init.d/firewall which does the same thing as what I am trying to do.

Regardless, I tried to set up a fake procd instance i.e. a simple bash script that slept forever and I was getting similar behavior.

The reason why I can't use the instances is because screend isn't a long running daemon. It's only purpose is to start/stop/restart GNU screens based on a uci config, not to actually maintain those screens.

OK, good point on the firewall.

I've rebuild your test setup from above and it behaves as you expect i.e. the reload is triggered every time. I'm on 18.06 though (I don't have a 19.07 system).

You can see the log from init.d (before and after) as well as the kernel logging from my /opt/screend script.

root@blah:~# logread -f -e screend &
root@blah:~# uci set screend.something=something_1 && uci commit && reload_config
root@blah:~# Mon Sep  6 09:41:52 2021 user.notice root: screend - calling reload_service
Mon Sep  6 09:41:52 2021 user.notice root: screend - reload_service called
Mon Sep  6 09:41:52 2021 user.warn kernel: [495737.001683] screend called with reload
root@blah:~# uci set screend.something=something_2 && uci commit && reload_config
root@blah:~# Mon Sep  6 09:41:58 2021 user.notice root: screend - calling reload_service
Mon Sep  6 09:41:58 2021 user.warn kernel: [495743.525241] screend called with reload
Mon Sep  6 09:41:58 2021 user.notice root: screend - reload_service called
root@blah:~# uci set screend.something=something_1 && uci commit && reload_config
root@blah:~# Mon Sep  6 09:42:03 2021 user.notice root: screend - calling reload_service
Mon Sep  6 09:42:03 2021 user.warn kernel: [495748.345971] screend called with reload
Mon Sep  6 09:42:03 2021 user.notice root: screend - reload_service called
root@blah:~# uci set screend.something=something_2 && uci commit && reload_config
root@blah:~# Mon Sep  6 09:42:07 2021 user.notice root: screend - calling reload_service
Mon Sep  6 09:42:07 2021 user.notice root: screend - reload_service called
Mon Sep  6 09:42:07 2021 user.warn kernel: [495752.599123] screend called with reload

As side note, if it is exactly 50/50 and alternates, I've usually seen that when there is an internal state kept somewhere like on/off, started/stopped which leads to that alternating pattern on each call.