Lazarus

Programming => General => Topic started by: eddy16391 on December 04, 2018, 11:52:22 am

Title: Self scheduled application
Post by: eddy16391 on December 04, 2018, 11:52:22 am
Hi everybody,
I'm trying to write a self scheduled application but it doesn't work. I'll explain better, we need an application that do a backup of some tables in a sql server and send everything to another server via SSH. The problem is that we don't have administrator permissions so we can't use the windows server scheduler. This is my code, I included it in a ttimer that run every hour, but with the first control it executes the procedure only from 01am to 02am:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Timer1Timer(Sender: TObject);
  2. begin
  3.   if (StrToTime(TimeToStr(Now))>StrToTime('01:00:00')) and (StrToTime(TimeToStr(Now))<StrToTime('02:00:01')) then
  4.   begin
  5.     try
  6.       last_sync := IdHTTP1.get('http://xx.xx.xx.xx/api/get_date');
  7.     finally
  8.       IdHTTP1.Free;
  9.     end;
  10.     last_sync:=last_sync.Substring(0, 19);
  11.     MSSQLConnection1.Connected:=True;
  12.     SQLTransaction1.Active:=True;
  13.     query:=TStringList.Create;
  14.     query.Clear;
  15.     query.Add('SELECT * FROM MG_DOC');
  16.     SQLQuery1.SQL:=query;
  17.     SQLQuery1.Active:=True;
  18.     CSVExporter1.FileName:='doctypes.csv';
  19.     CSVExporter1.Execute;
  20.     SQLQuery1.Active:=False;
  21.     query.Clear;
  22.     AbZipper1 := TAbZipper.Create(Application);
  23.     AbZipper1.FileName := 'export.zip';
  24.     AbZipper1.AddFiles('doctypes.csv',1);
  25.     AbZipper1.Password := 'xxx';
  26.     AbZipper1.Save;
  27.     AbZipper1.CloseArchive;
  28.     DeleteFile('doctypes.csv');
  29.     Process1.Create(nil);
  30.     Process1.Executable:='pscp.exe';
  31.     Process1.Parameters.Add('-P xxx -pw xxx "export.zip" xxx@xx.xx.xx.xx:"/var/www/html/xxx"');
  32.     Process1.Options := Process1.Options + [poWaitOnExit];
  33.     Process1.Execute;
  34.     DeleteFile('export.zip');
  35.     try
  36.       job := IdHTTP2.get('http://xx.xx.xx.xx/api/sync');
  37.     finally
  38.       IdHTTP2.Free;
  39.     end;
  40.     SQLTransaction1.Active:=False;
  41.     MSSQLConnection1.Connected:=False;
  42.     query.Free;
  43.     SQLQuery1.Free;
  44.     CSVExporter1.Free;
  45.     AbZipper1.Free;
  46.     Process1.Free;
  47.   end;
  48. end;

The problem is that it works only one time and not every night, despite the program is still running.
Any suggestion? Thank you!
Title: Re: Self scheduled application
Post by: Thaddy on December 04, 2018, 12:12:08 pm
The code is not that bad, but it belongs in a service/daemon and not an application. Or a cron job under linux.
Title: Re: Self scheduled application
Post by: balazsszekely on December 04, 2018, 12:25:02 pm
The code is not that bad, but it belongs in a service/daemon and not an application. Or a cron job under linux.
In my opinion the code is far from optimal. It will do the same thing over and over again between 1 AM and 2 AM, especially if the interval is small, most likely leading to an exception. You need something like this(not tested):
Code: Pascal  [Select][+][-]
  1.  TForm1 = class(TForm)
  2.     Timer1: TTimer;
  3.     procedure Timer1Timer(Sender: TObject);
  4.   private
  5.     FLastUpdate: TDateTime;
  6.     FBusyUpdating: Boolean;
  7.     function NeedToUpdate: Boolean;
  8.   public
  9.  
  10.   end;
  11. //...
  12.  
  13. uses dateutils;
  14.  
  15. function TForm1.NeedToUpdate: Boolean;
  16. var
  17.   CurTime: TDateTime;
  18. begin
  19.   CurTime := Now;
  20.   Result := (HoursBetween(CurTime, FLastUpdate) >= 23) and (HourOf(CurTime) >= 1) and (HourOf(CurTime) <= 2)
  21. end;
  22.  
  23. procedure TForm1.Timer1Timer(Sender: TObject);
  24. begin
  25.   if FBusyUpdating then
  26.     Exit;
  27.  
  28.   if NeedToUpdate then
  29.   begin
  30.     FBusyUpdating := True;
  31.     try
  32.       try
  33.         //Update process here
  34.         FLastUpdate := Now;
  35.       except
  36.         //log error here
  37.       end;
  38.     finally
  39.       FBusyUpdating := False;
  40.     end;
  41.   end;
  42. end;
Title: Re: Self scheduled application
Post by: eddy16391 on December 04, 2018, 12:33:16 pm
The interval is set as 1 hour, so the procedure is started just once.
The problem is that the first time the procedure is started correctly, but the next nights it doesn't start the procedure.
Title: Re: Self scheduled application
Post by: balazsszekely on December 04, 2018, 01:15:53 pm
Quote from: eddy
The interval is set as 1 hour, so the procedure is started just once.
OK, but what happens if something goes wrong during the backup? You should give your application at least a few chances to complete the job. If you set the interval to 5-10 minutes, you have 6-12 try in one hour. Once the backup is successfully completed, the above code(see my previous post) will prevent further attempts. 

Quote from: eddy
The problem is that the first time the procedure is started correctly, but the next nights it doesn't start the procedure.
Maybe there is an exception somewhere in the timer's code. You should use more try except blocks and/or log the executed lines.
Title: Re: Self scheduled application
Post by: Josh on December 04, 2018, 01:26:47 pm
Hi
Not tested below code; but I would run interval at say 1 minute or less, even every seconds should have no impact and record when the last backup was successful and check from there.

Code: [Select]
var my_backup_schedular_is_backing_up_data:boolean;
    last_run_date:TDateTime=0;
    hrs,mins,sec,msec:word;
   
    backup_was_successfull:boolean=false; // set this to true if backup of data completed without error;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  // check if backing up data;
  If my_backup_schedular_is_backing_up_data then exit;
  // now check if backup has already been run today
  if date<>last_run_date then
  begin
    // the date is new so now check if its the correct time to start a backup
    decodetime(time,hrs,mins,sec,msec);
    if hrs=1 then
    begin
      my_backup_schedular_is_backing_up_data:=true; // stop timer re-entering
      // so its a new date and its 1 oclock
      // do my data backup stuff

     .. set backup_was_successfull to true if backup completed without error

      // set last_run_date to todays date if backup successful
      if backup_was_successfull then last_run_date:=date;  // if failed then it will retry until its not 1am
      my_backup_schedular_is_backing_up_data:=false; // allow backup to start again.
    end;
  end;
 end;                     
Title: Re: Self scheduled application
Post by: Thaddy on December 04, 2018, 02:19:39 pm
The code is not that bad, but it belongs in a service/daemon and not an application. Or a cron job under linux.
In my opinion the code is far from optimal. It will do the same thing over and over again between 1 AM and 2 AM, especially if the
In my opinion the code is not that bad,certainly not optimal, but/and is what he intends to do.
Any pointers given should be in the direction of his intend.
TinyPortal © 2005-2018