Hi,
I'm having a very annoying problem with session management.
I designed a 3tier application using delphi rtc.
The application is running with several clients and one server.
After 10 min (or more ) of inactivity, the client freezes. (anyone of them).
No matter what I try on the client side, I'm not able to reconnect to the server.
HttpClient.MultiThreaded := True;
HttpClient.UseWinHTTP := False;
HttpClient.AutoConnect := True;
HttpClient.ReconnectOn.ConnectError := True;
HttpClient.ReconnectOn.ConnectFail := True;
HttpClient.ReconnectOn.ConnectLost := True;
Those events are hooked to the rtcHttpclient:
procedure TmdwClient.HttpClientConnectError(Sender: TRtcConnection;
E: Exception);
begin
if Assigned(FOnConnectionStatus) then FOnConnectionStatus( Self, csError, E );
end;
// #1 After 10min or more this event is fired
// I want to reestablish a connection, but all I get from the server is a timeout error.
procedure TmdwClient.HttpClientSessionClose(Sender: TRtcConnection);
begin
if Sender.inMainThread then begin
HttpClient.Disconnect;
if Assigned( FOnLogoff ) then
FOnLogoff(Self);
end
else
Sender.Sync(HttpClientSessionClose);
end;
procedure TmdwClient.HttpClientSessionOpen(Sender: TRtcConnection);
begin
if Sender.inMainThread then begin
if Assigned( FOnLoginRequired ) then
// Aqui iremos retornar um Login e senha que serão verificados
FOnLoginRequired( Self );
end
else
Sender.Sync(HttpClientSessionOpen);
end;
The code that freezes the client application is :
if not FInGetRows then begin
FInGetRows := True;
try
lFunc := glbClient.cmDataset.Data.NewFunction('Dataset');
lFunc.asString['Type'] := FParams.Values['Type']; // Table ou Query
lFunc.asString['TableName'] := FParams.Values['TableName'];
lFunc.asString['IndexFieldNames'] := FParams.Values['IndexFieldNames'];
lFunc.asString['KeyValue'] := FParams.Values['KeyValue'];
lFunc.asString['SQL'] := FParams.Values['SQL'];
// Buscando dados
lResultSet := glbClient.cmDataset.Execute(True,10); // #2 I was using "Execute" without parameters
// Precisamos dos campos e dos dados
if lResultSet.isType = rtc_Record then
// Aqui iremos preencher o dataset com as linhas retornadas!
TBOrtcUtils.rtcRecord2Dataset( lResultSet.asRecord, Self );
finally
FInGetRows := False;
end;
end;
When calling
Execute(True,10) the application became responsive.
But still the call returns a TimeoutError, which is strange because the server is listening. All other workstations are running fine.
But If any of them keep idle for over 10min, the same thing happens. So it's not the hardware. It's me.. again
Let me describe the server side now.
This application reads user information from a database, so when opening a session, I must know the user login in order to get the data required by the application.
When the session ends, everything is destroyed.
This is the relevant server side code:
procedure TmdwServer.HTTPserverSessionOpen(Sender: TRtcConnection);
var
lSessionData : TBOSessionData;
begin
lSessionData := TBOSessionData.Create;
TrtcDataServer( Sender ).Session.Obj['SessionData'] := lSessionData;
FLog.LogMsgFMT( 'Sessão aberta para -> %s:%s',[Sender.PeerAddr, Sender.PeerPort] );
end;
procedure TmdwServer.HTTPserverSessionClose(Sender: TRtcConnection);
var
lSessionData : TBOSessionData;
begin
lSessionData := TBOSessionData( TrtcDataServer( Sender ).Session.Obj['SessionData'] );
// Retirando objeto da lista de sessões
TrtcDataServer( Sender ).Session.Obj['SessionData'] := nil;
lSessionData.Free;
FLog.LogMsgFMT( 'Sessão encerrada para -> %s:%s',[Sender.PeerAddr, Sender.PeerPort] );
end;
There's an important remote function that must be called when the session is created in order to load the user credentials:
procedure TmdwServer.fncCheckCredencialsExecute(Sender: TRtcConnection;
Param: TRtcFunctionInfo; Result: TRtcValue);
var
lLogin,
lPwd ,
lVersion : String;
lBOUser : TBOUser;
lBOSession : TBOSessionData;
begin
lLogin := Param.AsString['Login'];
lPwd := Param.AsString['PWD'];
lBOSession := TBOSessionData( TrtcDataServer( Sender ).Session.Obj['SessionData']);
lBOUser := TBoUser.Create( lBOSession );
try
if lBOUser.CheckCredencials( lLogin, lPwd ) then begin // #3
{... some irrelevant code here }
end
finally
lBOUser.Free;
end;
end;
lBOUser.CheckCredencials( lLogin, lPwd ) will load the user information in my session class (SessionData) that will be used by other remote functions.
That's why this function is important.
The session ends gracefully, but I don't understand why I can't reconnect the client.
Any advice?
Clément