Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to resume/retry a broken TADOConnection across the application?

I have a data module with a global TADOConnection (with the default KeepConnection set the true). There are numerous datasets and queries in my existing application that use this global TADOConnection.

I was wondering if there is some smart way to resume/retry the ado connection in case of a short network disconnection? (this situation happens sometimes with clients who have a not so stable connections).

Its easy to reproduce what I need. simply open TADOConnection on start-up. open some TADODataSet, and then disable and enable your "Local Area Connection". if you try to refresh the dataset, an EOleException exception is raised

"Connection failure"

or

"[DBNETLIB][ConnectionWrite (send()).]General network error. Check your network documentation"

If I restart the application all is good.

No events are fired by the TADOConnection at the time of network disconnections. and TADOConnection.Connectedremains true

of course I could use a try/catch for every TDataSet.Open or Execute but I'm looking for some "centralized" solution for my large application. so in case of "Connection failure" I could know which dataset is trying to open, and retry.

like image 248
zig Avatar asked Jun 24 '15 10:06

zig


1 Answers

No never firing at the time of network disconnections. But you can check connection before every command. So if AdoConnection disconnected, you can reconnect and execute your command after this.

If you wanna centralized solution and you have 1 Connection, you can do that like this;

Const
  ConnectionTestString=' '; //Yes, it's work on Sql Server. If doesnt your db, you can use 'Select 1'

Procedures;

Procedure TDM.GetCommandResult_Conn(CText:String;Connection : TAdoConnection);
var Ado_Ds_Tmp:TAdoCommand;
Begin
    Ado_Ds_Tmp:=TAdoCommand.Create(self);
    try
      Ado_Ds_Tmp.Connection:=Connection;
      Ado_Ds_Tmp.ParamCheck := False;
      Ado_Ds_Tmp.CommandText:=CText;
      try
        Ado_Ds_Tmp.Execute;
      except
        DM.RaiseExceptionCreate('Error ! Command, ('+StrToList(CText, ' ')[0]+')');
      end;
    finally
      Ado_Ds_Tmp.Destroy;
    end;
end;

procedure TDM.ADOConnection1WillExecute(Connection: TADOConnection;
  var CommandText: WideString; var CursorType: TCursorType;
  var LockType: TADOLockType; var CommandType: TCommandType;
  var ExecuteOptions: TExecuteOptions; var EventStatus: TEventStatus;
  const Command: _Command; const Recordset: _Recordset);
var
   ErrorLogFileName : string;
   ErrorFile : TextFile;
   ErrorData : string;
   Msg : String;
begin
  try
    if (CommandText<>ConnectionTestString) then begin
      DM.GetCommandResult_Conn(ConnectionTestString, Connection);
    end;
  except
    try
      try
        Connection.Connected := False;
      except
      end;
      try
        Connection.ConnectionString := AdoConnectionString;
        Connection.Mode:=cmShareDenyNone;
      finally
        try
          Connection.Connected := True;
          // If you wanna log for frequency 
          ErrorLogFileName := ChangeFileExt(Application.ExeName,'.error.log');
          AssignFile(ErrorFile, ErrorLogFileName);
          if FileExists(ErrorLogFileName) then
            Append(ErrorFile)
          else
            Rewrite(ErrorFile);
          try
            ErrorData := Format('%s : %s : %s (%s / %s)',[DateTimeToStr(Now), 'Disconnected but we reconnect.', '', 'UserName : '+DBUser, 'Client : '+GetComputerNetName]);
            WriteLn(ErrorFile,ErrorData);
          finally
            CloseFile(ErrorFile)
          end;
        except
          DM.RaiseExceptionCreate('ReConnection Failed!');
        end;
      end;
    except
    end;
  end;
end;

Any question?

like image 163
Ercument Eskar Avatar answered Nov 13 '22 15:11

Ercument Eskar