Thinking out loud ....
I have a flow in an asynchronous message bus (MQTT) system which is experiencing oscillations due to event starvation.
The original design allowed the sensors to govern the event cadence. This worked absolutely fine when all my temperature sensors output every 10 seconds.
I have replaced them with battery operated sensors which are a lot more frugal about their transmissions and will not resend a "same value" twice within (by default) 10 minutes.
My system uses transient, expiring state to control the downstream. So, when a temperature arrives for a zone and heating is required a message is published to demand heating with an expiry of, 1 minute. If that requires a radiator it gets switched on for 3 minutes. If it requires the boiler (it will) that gets switched on for 10 minutes. Every time a temperature arrives for that zone while there are active "timers" the timers will be reset. Once updates stop, the schedule stops requesting etc. the demands and control states expire.
These 1min, 3min, 10min are the core "temporal hysteresis" preventing "oscillation around the trigger". There are other forms of hysteresis not relevant.
So, the 1min timeout doesn't really effect anything. It has to expire first before the others for radiator and boiler will start counting down. So a single "below spec" temp which causes at least one schedule to request heating will cause any relevant radiator to be on for a minimum of 4 minutes. The boiler will be on for a minimum of 11mins.
Originally I have been setting all those temp sensors config to send "at least every 5 minutes". Trouble is, I have quite a few of these now and I am replacing at least one battery every few months. Thats not a problem, but usually they lose their config when you swap the battery and reconfiguring them is a PITA. So, some slip through and return to only updating every 10mins if the temp doesn't change.
I want to decouple the "cadence" away from the sensors transmission rate. So I basically need either a synthetic event that causes all schedules to rerun all retained values, or I add a "repeater" service to the bus which will periodically retransmit temperature data more periodically. I "could" make the schedules "poll" retained state, but I want to still retain the instant response to events.
The repeater service sounds more fitting, as then nothing else needs to know it exists. Compartmentalisation of responsibility.
The repeater service will subscribe to the tree of topics needing synthetic events of retained state.
When a value is received its timestamp is checked for expiry. If expired it's dropped. If not expired it is retained in a map.
The service will wake a thread and process the contents of the map, data which still hasn't expired will be retransmitted. Data that has expired will be removed from the map. (EDIT: The service shall not receive or shall ignore it's own retransmissions! EDIT: resent="true"
)
An instance of the service will take, a topic expression to operate on, a period to refresh data over, the "max age" of data to retransmit before discarding.
That period can be 1 minute, giving me a near guaranteed 1 minute cadence on the consumers.
The max age for a domestic air temp can be 30 minutes. The metric here being not how fast the temperature can change, but how slowly it can. 30mins gives the heating system enough time to have responded. Even if the temperature remains the same, and the sensor never resends same value, we will keep assuming the temperature has not changed and so we keep the heating on. If it still hasn't changed after 30mins it's broken and so it will expire and the heating will turn off.
I'm going to start writing a book on "How to overcomplicated domestic heating control".