0

How to implement a Cron task in Ada ?

The precision of the Cron task can be 1 second; sub-seconds are not necessary.

with Ada.Text_IO; 
With Ada.Calendar;
With Ada.Calendar.Formatting;

use Ada.Text_IO;
use Ada.Calendar;
use Ada.Calendar.Formatting;

package body Cronjob is
  
   procedure Run_Cron_Task is

      task T;

      task body T is
      begin
        
         loop
            
            declare
               Now:Time:=Ada.Calendar.Clock;
               My_Hour:Hour_Number:=Ada.Calendar.Formatting.Hour(Now);
               My_Minute:Minute_Number:=Ada.Calendar.Formatting.Minute(Now);
               My_Second:Second_Number:=Ada.Calendar.Formatting.Second(Now);
            begin 
               
               if My_Hour = 01 And My_Minute = 00 And My_Second = 01 then  -- time 01:00:00 
                  
                  Put_Line("We are running Cronjob at Time");
                  Put_Line(Image(Now));
                  
                  delay 1.0; -- extra delay ..make that the crone doesn't get triggered twice
                  
               end if;
      
               delay 0.5; -- not sure about the delay here
               
            end;
            
         end loop;
         
      end T;
      
   begin
      
    null;
      
   end Run_Cron_Task;
   

end Cronjob;

Maybe somebody have an more elegant way how to implement that?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
mcxbain
  • 89
  • 5
  • It looks like your post is mostly code; please add some more details. I think the Details are in the code. – ino Apr 22 '22 at 19:30
  • Also consider [_How can I programmatically create a new cron job?_](https://stackoverflow.com/q/610839/230513) – trashgod Apr 22 '22 at 22:11
  • 2
    This depends on what you mean by a cron task. Traditionally, in Unix systems, this means to modify the crontab to include the desired program at the desired times. But your example seems to be to use a task to perform some activity at a set time. Usually that is done using a **delay until** statement to delay until the desired time, then perform the action. – Jeffrey R. Carter Apr 23 '22 at 10:33
  • thank you Jeffrey, use a task to perform some activity at a set time. That is exactly what i mean. Is there somewhere an example of this ? – mcxbain Apr 23 '22 at 11:19
  • 1
    An example of @JeffreyR.Carter's [suggestion](https://stackoverflow.com/questions/71973498/how-to-implement-an-cronjob-in-ada#comment127187698_71973498) is shown in the [`delay`](https://www.adaic.org/resources/add_content/standards/12rm/html/RM-9-6.html#p40) API. – trashgod Apr 23 '22 at 15:58

1 Answers1

0

Adopting the delay example:

task body T is
   use Ada.Calendar;
   Now : Time := Clock;
   --  Next will be the next moment in time for which we want to 
   --  execute jobs. we initialize it to the nearest full second.
   --  that may be earlier or later than Now.
   Next : Time := Time_Of (
     Year    => Year  (Now),
     Month   => Month (Now),
     Day     => Day   (Now),
     Seconds => Day_Duration'Round (Seconds (Now))
   );
begin
   loop
      --  to be robust, we iterate through all seconds from Next to Now
      --  here. this guarantees that jobs get executed even when seconds
      --  are skipped (because a job takes too long or because other
      --  tasks take away our precious CPU time).
      --
      --  on first iteration, this may be completely skipped if we rounded up.
      while Next <= Now loop
         declare
            My_Hour   : Hour_Number   := Formatting.Hour   (Next);
            My_Minute : Minute_Number := Formatting.Minute (Next);
            My_Second : Second_Number := Formatting.Second (Next);
         begin
            --  call any jobs scheduled for current time here
            -- ... skip ...
         end;
         Next := Next + 1;
      end loop;
      --  now delay until we reach our Next second.
      delay until Next;
      Now := Clock;
   end loop;
end T;

You can make this more efficient if you increase Next until you actually find a job that wants to be executed, see code below. However be aware that this has some pitfalls:

  • if there is no job, this task will never sleep and eventually overflow its Next variable.
  • if you can dynamically add jobs in some other task, this task will skip any newly added jobs before the next job that has already been known when it went to sleep.
-- instead of the while loop
loop
   declare
      My_Hour   : Hour_Number   := Formatting.Hour   (Next);
      My_Minute : Minute_Number := Formatting.Minute (Next);
      My_Second : Second_Number := Formatting.Second (Next);
   begin
      if Job_Available_For (My_Hour, My_Minute, My_Second) then
         exit when Next > Now;
         --  call any jobs scheduled for current time here
         -- ... skip ...
      end if;
      Next := Next + 1;
   end;
end loop;
flyx
  • 35,506
  • 7
  • 89
  • 126