#1 2015-01-19 09:41:40

EvaF
Member
Registered: 2014-07-19
Posts: 40

OnHttpThreadTerminate event

Hi,
first of all thank you  for a great framework.

While troubleshooting memory leaks in my webservices I  ran into a problem with releasing memory allocated for OleDBConnections.

I use  TInterfacedObject class, in sicPerSession mode.

here is the scenario:
I implement  my own OnHttpThreadTerminate  and the original OnHttpThreadTerminate is stored in fOnHttpThreadTerminate variable

here is the relevant excerpt:

  procedure TJSONServer.MyHttpThreadTerminate(Sender:TThread);
  begin
    fPropsMSSql.EndCurrentThread;
    fOnHttpThreadTerminate(Sender);
  end;
...
...
     fHTTPServer := TSQLHttpServer.Create(
                            aPORTNAME,                   
                            [fServerDB],                
                            aHostName,   
                            useHttpApiRegisteringURI,   
                            32,                         
                            secSSL);                 
      fOnHttpThreadTerminate :=fHTTPServer.HTTPSErver.OnHttpThreadTerminate;
      fHTTPServer.HTTPSErver.OnHttpThreadTerminate := MyHttpThreadTerminate;

I wondered why my MyHttpThreadTerminate wasn't called at all.. I have found out that it is caused by clones of THttpApiServer, that still point to the original onTerminated event procedure.
I have modified your code in SynCrtSock.pas like this:

  THttpServerGeneric = class(TNotifiedThread)
  protected
      ...
       procedure setOnTerminate(pValue: TNotifyThreadEvent);
  public
      ...
    property OnHttpThreadTerminate: TNotifyThreadEvent read fOnTerminate write setOnTerminate;
  end;
 ....
 ...
procedure THttpServerGeneric.setOnTerminate(pValue: TNotifyThreadEvent);
var i : integer;
begin
  fOnTerminate := pValue;
  if (self is THttpApiServer) and assigned ((self as THttpApiServer).Clones) and
    not assigned((self as THttpApiServer).fowner ) then
  begin
    for i := 0 to (self as THttpApiServer).Clones.count - 1 do
    begin
      THttpServerGeneric( (self as THttpApiServer).Clones[i]).OnHttpThreadTerminate := pValue;
    end;
  end;
end;

after this modification the  "MyHttpThreadTerminate" is now allways invoked

Eva

Offline

#2 2015-01-19 21:56:26

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: OnHttpThreadTerminate event

I've fixed THttpApiServer.OnHttpThreadTerminate event setting propagation to its clones.
See http://synopse.info/fossil/info/b87959a094

My implementation is a little bit cleaner, since it uses an overriden method, but is more or less the same.

Thanks for your feedback!

Offline

#3 2015-01-20 19:34:57

EvaF
Member
Registered: 2014-07-19
Posts: 40

Re: OnHttpThreadTerminate event

ok, you are right - I could not forsee all ramifications - therefore I used the more cumbersome variant..
I had another two little silly requests:
1) to expand the set  (SysCommon.pas)

 
 IsWord: set of byte =
    [ord('0')..ord('9'),ord('a')..ord('z'),ord('A')..ord('Z'),ord('{'),ord('}'),ord('-'),ord('_')];

  // instead of current set  

 IsWord: set of byte =
    [ord('0')..ord('9'),ord('a')..ord('z'),ord('A')..ord('Z')];

I often use TSynSQLTableDataSet and I need to fast locate the key - mostly of type Guid

2) while searching for a solution to the Onterminate problem, I stumbled on a small potential problem with EnterCriticalSection  ( the leaveCriticalSection is not executed if CurrentThreadConnection exists )

function TSQLDBConnectionPropertiesThreadSafe.ThreadSafeConnection: TSQLDBConnection;
var i: integer;
begin
  case fThreadingMode of
  tmThreadPool: begin
    EnterCriticalSection(fConnectionCS);
    try
      i := CurrentThreadConnectionIndex;
      if i>=0 then begin
        result := fConnectionPool.List[i];
        if result.IsOutdated then
          fConnectionPool.Delete(i) else // release outdated connection
          exit;                                  // <---------- here
      end;
      result := NewConnection;
      (result as TSQLDBConnectionThreadSafe).fThreadID := GetCurrentThreadId;
      fLatestConnectionRetrievedInPool := fConnectionPool.Add(result)
    finally
      LeaveCriticalSection(fConnectionCS);
     end;
  end;
  tmMainConnection:
    result := inherited GetMainConnection;
  else
    result := nil;
  end;
end;

Eva

Offline

#4 2015-01-20 19:58:54

EMartin
Member
From: Buenos Aires - Argentina
Registered: 2013-01-09
Posts: 332

Re: OnHttpThreadTerminate event

The "exit" command always execute the finally section when is inside of the try ... finally.


Esteban

Offline

#5 2015-01-21 18:33:19

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: OnHttpThreadTerminate event

1) I would not change the default definition of 'word' to include the GUID values.
It does not make much sense...
But you can use your own method for searching.

2) As EMartin stated, there is no problem in the current implementation: the "exit" runs the "finally" part.
Just check with the debugger.
wink

Offline

Board footer

Powered by FluxBB