Nein, bitte nicht mit diesem
Exception Handling.
Wenn du an etwas Generellem interessiert bist, dann wäre hier etwas
Delphi-Quellcode:
type
Closure = record
class function Retry( const AProc: TProc; const MaxRetryCount: Integer = 0 ): TProc; overload; static;
class function Retry<T>( const AProc: TProc<T>; const MaxRetryCount: Integer = 0 ): TProc<T>; overload; static;
class function Retry<T1, T2>( const AProc: TProc<T1, T2>; const MaxRetryCount: Integer = 0 ): TProc<T1, T2>; overload; static;
class function Retry<T1, T2, T3>( const AProc: TProc<T1, T2, T3>; const MaxRetryCount: Integer = 0 ): TProc<T1, T2, T3>; overload; static;
end;
{ Closure }
class function Closure.Retry( const AProc: TProc; const MaxRetryCount: Integer ): TProc;
begin
Result := procedure
var
LRetryCount: Integer;
begin
LRetryCount := 0;
while True do
try
AProc( );
Exit;
except
Inc( LRetryCount );
if LRetryCount >= MaxRetryCount
then
raise;
end;
end;
end;
class function Closure.Retry<T1, T2, T3>( const AProc: TProc<T1, T2, T3>; const MaxRetryCount: Integer ): TProc<T1, T2, T3>;
begin
Result := procedure( Arg1: T1; Arg2: T2; Arg3: T3 )
begin
Retry(
procedure
begin
AProc( Arg1, Arg2, Arg3 );
end, MaxRetryCount )( );
end;
end;
class function Closure.Retry<T1, T2>( const AProc: TProc<T1, T2>; const MaxRetryCount: Integer ): TProc<T1, T2>;
begin
Result := procedure( Arg1: T1; Arg2: T2 )
begin
Retry(
procedure
begin
AProc( Arg1, Arg2 );
end, MaxRetryCount )( );
end;
end;
class function Closure.Retry<T>( const AProc: TProc<T>; const MaxRetryCount: Integer ): TProc<T>;
begin
Result := procedure( Arg: T )
begin
Retry(
procedure
begin
AProc( Arg );
end, MaxRetryCount )( );
end;
end;
Im Übrigen sollten die Aufrufe
FDB.TuDies
und
FDB.TuDas
sich selber um den Lock (wieso eigentlich
Mutex, brauchst du das Session- bzw. System-Global? Sonst würde ein
TMonitor
reichen) kümmern, denn der scheint ja immanent wichtig zu sein, also gehört der in diese Methoden rein.
Delphi-Quellcode:
type
TFoo = class
public
procedure Foo( AParam: Integer );
procedure Bar( AParam1, AParam2: Integer );
end;
{ TFoo }
procedure TFoo.Bar( AParam1, AParam2: Integer );
begin
TMonitor.EnterAutoLeave( Self ); {Lock}
Writeln( 'TFoo.Bar(', AParam1, ',', AParam2, ')' );
end;
procedure TFoo.Foo( AParam: Integer );
begin
TMonitor.EnterAutoLeave( Self ); {Lock}
Writeln( 'TFoo.Foo(', AParam, ')' );
end;
Dieses
TMonitor.EnterAutoLeave
kommt durch einen
class helper
von mir, der ein Interface zurückliefet und dafür für das automatische Verlassen sorgt. Dadurch wirkt der Code gleich viel entspannter.
Aufruf von der gesamten Hütte ist jetzt ein gemütlicher Spaziergang
Delphi-Quellcode:
procedure Test;
var
LFoo: TFoo;
begin
LFoo := TFoo.Create;
try
Closure.Retry<Integer>( LFoo.Foo, 10 )( 42 );
Closure.Retry<Integer, Integer>( LFoo.Bar, 10 )( 08, 15 );
finally
LFoo.Free;
end;
end;
Lustig gell?
UPDATE
Ok, das mit dem
Mutex habe ich jetzt auch verstanden, damit garantierst du, dass nur einer global auf die Datenbank zugreift. Ansonsten schmeisst der
Mutex eine
Exception. Das ändert aber nichts an meinem Vorschlag, ausser, dass man den Closure noch erweitert um ein Predicate, dass den
Exception-Typ bekommt und dort entschieden wird, ob da wirklich weitergemacht werden soll, denn eine
EAccessViolation
ist nichts, wo ich es nochmals versuchen müsste, da ich ja eigentlich auf nur auf den
Mutex warte.