TaskScheduler icon indicating copy to clipboard operation
TaskScheduler copied to clipboard

Time elapsed since the last execution of a task that has already finished its interactions.

Open georgevbsantiago opened this issue 9 months ago • 7 comments
trafficstars

Hello, Thank you for this awesome library.

I'm trying to understand if there is a way to get the time elapsed since the last execution of a task that has already finished its interactions.

It would be something similar/equal to the elapsed() method from the library Ticker

Ticker Elapsed Time uint32_t Ticker::elapsed() Returns the time passed since the last tick in ms or us depending on mode.

In my use case, I'm checking a set of conditions and one of them is the time elapsed since the last execution of a task that has already finished its interactions.

The way I found to solve my problem:

unsigned long millis_check_OFF_to_on;

void uplink_imediato_function();
Task uplink_imediato_task(50, 1, &uplink_imediato_function, &loop_Tasks_Scheduler, false);

if(status_current_previous == false &&
   ((millis() - millis_check_OFF_to_on) >= ( 1 * TASK_MINUTE))) {

   uplink_imediato_task.restart();

   millis_check_OFF_to_on = millis();

}

If there was an approach similar to elapsed() from the Ticker library, then I could use this way:

void uplink_imediato_function();
Task uplink_imediato_task(50, 1, &uplink_imediato_function, &loop_Tasks_Scheduler, false);

if(status_current_previous == false &&
  uplink_imediato_task.elapsed() >= ( 1 * TASK_MINUTE))) {

   uplink_imediato_task.restart();

}

Is there something similar to Ticker's elapsed() method in the TaskScheduler library?

georgevbsantiago avatar Jan 27 '25 23:01 georgevbsantiago

Hi @georgevbsantiago - based on the description of elapsed() I am not sure it works they way you describe, I think it is the time since last Ticket tick, no?

Regardless, no - this functionality is not available in TS - I might implement it in the new version. Somehow in all those years no one, including me, needed this :) Thanks for the idea.

arkhipenko avatar Jan 28 '25 12:01 arkhipenko

In the case mentioned above, the objective is to obtain the time elapsed since the last execution of a task that has already finished its interactions.

However, from the context above it would be possible to extract two new implementations:

  • Time elapsed since the last execution of a task that has already finished its interactions;
  • Time elapsed since the last iteration of a task that is still active and running;

Thank you for considering this feature. It will help in tasks that involve performing uplink, as illustrated in the code above.

georgevbsantiago avatar Jan 28 '25 14:01 georgevbsantiago

I think it is relatively easy for me to capture the exact moment ( millis() ) when the task's callback was invoked (entered) and finished (returned to scheduler). Same for onEnable() and onDisable() I believe all other stats could be calculated from there. Do you agree?

arkhipenko avatar Jan 28 '25 20:01 arkhipenko

However, this presents a challenge will millis rollover: Case 1: (all good) task started at 3000 and finished at 3500

Case 2: task started and have not finished yet: start = 3000, finish =? 0? 0 is a valid millis value... what if the task started 500 millis before rollover? Needs to have an extra value indicating whether the task is currently executing or not - and that will ONLY work (return true) in the multi-threaded environment, since in cooperative only one task is running at a time what if tast started at millis = 0? And if task is not active and start time = 0 - did it start at 0 or never run? I guess you can check the gerRunCounter() for that...

it is quite possible that task start will be 4294967200 and finish 5 (runtime of 100 ms with a rollover after passing 4,294,967,295 - UINT32_MAX) - finish is less than start.. Brrrr

All of those are somewhat edge cases. but yet, they can confuse the logic

arkhipenko avatar Jan 28 '25 20:01 arkhipenko

Perhaps the first case (which was the one in my example) is the easiest to implement:

  • Time elapsed since the last execution of a task that has already finished its interactions;

The second case may have many exceptions and complexities.

  • Time elapsed since the last iteration of a task that is still active and running;

I believe that the first case would already be an excellent feature to be added.

You can assign -1 to tasks that have never been executed or activated. If the task has already been executed at some point and is finished, the time (milliseconds) since its termination.

It is not the same use case as long timeUntilNextIteration (Task& aTask); , but you can apply a similar logic to the values ​​used -1, 0 ...

georgevbsantiago avatar Jan 29 '25 00:01 georgevbsantiago

for better resolution - micros() is a better choice. same rollover issues, but still better timing resolution...

misc-protolabs avatar Jan 29 '25 22:01 misc-protolabs

You can assign -1 to tasks that have never been executed or activated.

Cannot use negative numbers - millis() is uint32_t

arkhipenko avatar Jan 29 '25 22:01 arkhipenko

Actually, this is very easy to implement in your code without updates to the library: You can use TASK_LTS - local task storage pointer to store the millis() value when the task is disabled, using the onDisable() method, and then compare to that value if the tast is not enabled anymore.

Scheduler ts;
Task uplink_imediato_task(100,2,&callback,&ts,true, null, &callbackOD); 

void callbackOD() {
   uplink_imediato_task.setLtsPointer((void *) millis());
}

then in your main code:

if ( !uplink_imediato_task.isEnabled() && (millis() - (uint32_t) uplink_imediato_task.getLtsPointer()) > TASK MINUTE) ...

arkhipenko avatar Sep 21 '25 23:09 arkhipenko