arkhipenko / TaskScheduler

Cooperative multitasking for Arduino, ESPx, STM32, nRF and other microcontrollers
http://playground.arduino.cc/Code/TaskScheduler
BSD 3-Clause "New" or "Revised" License
1.26k stars 230 forks source link

Disable "catch up" mechanism #72

Closed Foxbond closed 5 years ago

Foxbond commented 5 years ago

It is rather question than a bug - how I can disable "catch up" mechanism?

Let say I have "heartbeat" task, every 10 seconds it will ping a server. When eth connection will be broken it will enter "reconnect" routine until connection is restored. Let say connection will be restored after 1h - after that "heartbeat" task will be fired 360 times flooding server.

arkhipenko commented 5 years ago

You can just call heartbeat.restartDelayed(); as the last instruction of reconnect and heartbeat will start fresh. You can also call enableDelayed() as the last instruction of heartbeat 's callback to avoid catchup (since that would reschedule heartbeat from the current point in time. You can also use getOverrun() method to assess if you are in the catch-up mode. If getOverrun() returns negative value - you are in the catchup for that many milliseconds. (Need to compile with _TASK_TIMECRITICAL compilation option).

However, the way you are describing reconnect it is exhibiting a non-cooperative behavior (blocking everyone until the connection is restored). I would create both heartbeat and reconnect as periodic tasks (say running every 10 seconds) When heartbeat detects that the server does not respond, it starts reconnect and disables itself and all other tasks that rely on the connection. When reconnect finally reconnects to the server it restarts heartbeat (and enables all other tasks as necessary) and disables itself. All of this is happening without the danger of catchup.

NOTE: By design, TS is scheduling tasks prioritizing schedule over interval . This means that if a task is supposed run every 10 seconds, but has been started on t=12 seconds due to delay of previous tasks, it will be scheduled to run next time at t=20 seconds (schedule is a priority) rather than t=22 seconds (interval is a priority). I found that schedule is a more common use case. I deliberately did not implement both because it puts additional decision logic into the main loop, which is optimized to be the least overhead possible.

Hope this helps.

Foxbond commented 5 years ago

Thanks for great explanation, it helped a lot.