Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: idHttp and CreatingAnonymousThread



Permlink Replies: 9 - Last Post: Dec 15, 2015 6:43 PM Last Post By: Eduardo Elias
Eduardo Elias

Posts: 319
Registered: 9/20/12
idHttp and CreatingAnonymousThread
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 1, 2015 3:51 AM
HI there...

XE2.4 VCL

I am using Indy with idHttpServer to serve rest requests to androids in my
local network.

It works very well and also the concurrency is just fine.

THe problem is that I have a limited time to complete each request, and there
is one in particular that is now very slow, due a comunication with RS232
with a slow device.

My question is if I could use CreateAnonymousThread to "detach" my code,
from inside the idHttp thread.

This is how I am set up the server:

FidHTTPServer := TidHTTPServer.Create;
FIdHTTPServer.KeepAlive := false;
FIdHTTPServer.ContextClass := TyClientContext;
FidHTTPServer.OnConnect := IdHTTPServerConnect;
FidHTTPServer.OnCommandGet := IdHTTPServerCommandGet;

And How I call the handler:

procedure TyHTTPServer.IdHTTPServerCommandGet(AContext: TIdContext; ARequestInfo:
TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
Context : TyClientContext;
begin
Context := TyClientContext(AContext);
Context.HandleRequest(ARequestInfo, AResponseInfo);
end;

I parse the request from inside my Handler and then call the apropriate function.
There is no in specific that is now slow and I wanted to detach with its
own context.

Trying to help my android client I have added this:

AResponseInfo.ContentText := CreateJSONResult('result', '0').AsString;
AResponseInfo.WriteHeader;
AResponseInfo.WriteContent;

In an attepmt to free the client from waiting longer. However the client
makes a new request too soon while the previous thread remains working.

There is a process of login on my server, it is not stateless, so I need
to have the thread finished to accept a new request, unless I detach it from
the thread.

Ideas?

Eduardo

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: idHttp and CreatingAnonymousThread
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 1, 2015 9:45 AM   in response to: Eduardo Elias in response to: Eduardo Elias
Eduardo wrote:

My question is if I could use CreateAnonymousThread to "detach"
my code, from inside the idHttp thread.

Like everything else in Indy, TIdHTTPServer's processing of client requests
is designed to be synchronous. By default, when you exit from your OnCommandGet
event handler, TIdHTTPServer will send a reponse to the client. You are
expected to populate the AResponseInfo with your final response data before
exiting the event handler.

That being said, there is one way to do what you are asking for.

Set TIdHTTPServer.KeepAlive to true, and then have your event handler set
AResponseInfo.HeaderHasBeenWritten to True, AResponseInfo.CloseConnection
to False, AResponseInfo.ContentText to a blank string, and AResponseInfo.ContentStream
to nil. This way, TIdHTTPServer will not automatically send a response to
the client, or close the socket connection, when the event handler exits.

Now, you can have your event handler launch a worker thread to process the
request asynchronously as needed. However, you will lose access to the ARequestInfo
and AResponseInfo objects (they are freed when the event handler exits),
so you will have to copy whatever ARequestInfo data you need, and you will
have to manually write the entire HTTP response headers and body directly
to the TIdContext socket.

There are also some risks. If the client disconnects, the TIdContext object
and its socket will be destroyed while your thread is still running, which
can cause your thread to crash. And by unblocking TIdHTTPServer, the client
is also free to send a new request to the server while your thread is still
processing a previous request. This might not be a bad thing, actually,
as it would allow you to implement HTTP pipelining, for instance (provided
you serialize your asynchronous responses so they get sent to the client
in the right order).

Trying to help my android client I have added this:

AResponseInfo.ContentText := CreateJSONResult('result', '0').AsString;
AResponseInfo.WriteHeader;
AResponseInfo.WriteContent;

In an attepmt to free the client from waiting longer.

That will free up the client, but it will not free up the server. And you
will not be able to send any further responses to the client, if you have
more data to send.

However the client makes a new request too soon while the previous
thread remains working.

Exactly. The client does not know what the server is doing. If you make
the server run asynchronously, there is nothing you can do to prevent the
client from sending a new request.

There is a process of login on my server, it is not stateless, so I
need to have the thread finished to accept a new request, unless I
detach it from the thread.

You need to track state information and have your event handler act according
to the current state. You can put state information in your TyClientContext
class, or you can use TIdHTTPServer's built-in session management (which
requires the client to support cookies). TIdHTTPServer has OnCreateSession,
OnSessionStart and OnSessionEnd events, and the ARequestInfo and AResponseInfo
objects have a Session property. You can use the TIdHTTPSession.Content
property to store state information. Just make sure the TIdHTTPServer.SessionState
property is True, and the TIdHTTPServer.SessionIDCookieName property has
a non-blank value assigned.

--
Remy Lebeau (TeamB)
Eduardo Elias

Posts: 319
Registered: 9/20/12
Re: idHttp and CreatingAnonymousThread
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 4, 2015 3:22 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Hello Remy,

Thanks for the answer!!

Just a quick very needed help on this:

My server recently started to sometimes consume 99% of the cpu.

It shouldn´t, I could not find anything I changed.

I use the idHttpServer with this basic parameters:

FidHTTPServer := TidHTTPServer.Create;
FIdHTTPServer.KeepAlive := false;
FIdHTTPServer.ContextClass := TyClientContext;
FidHTTPServer.OnConnect := IdHTTPServerConnect;
FidHTTPServer.OnCommandGet := IdHTTPServerCommandGet;

Then I have my context class created and the the process happens inside the
Handler, that exists placing a simple status anwser commonly.

I could see that happening on my PC only once, but in a customer it is frequent.
The request is processed and return normal, and then the program got 99%
cpu use.

It remains responding to request, but slower since it is use a lot of CPU.

At the customer seems that it finishes what was doing and go back to normal,
and that happens again after some requests answered.

Is there any of the idHttpServer properties that I am using as default that
could be causing this?

Eduardo

Eduardo wrote:

My question is if I could use CreateAnonymousThread to "detach" my
code, from inside the idHttp thread.
Like everything else in Indy, TIdHTTPServer's processing of client
requests is designed to be synchronous. By default, when you exit
from your OnCommandGet event handler, TIdHTTPServer will send a
reponse to the client. You are expected to populate the AResponseInfo
with your final response data before exiting the event handler.

That being said, there is one way to do what you are asking for.

Set TIdHTTPServer.KeepAlive to true, and then have your event handler
set AResponseInfo.HeaderHasBeenWritten to True,
AResponseInfo.CloseConnection to False, AResponseInfo.ContentText to a
blank string, and AResponseInfo.ContentStream to nil. This way,
TIdHTTPServer will not automatically send a response to the client, or
close the socket connection, when the event handler exits.

Now, you can have your event handler launch a worker thread to process
the request asynchronously as needed. However, you will lose access
to the ARequestInfo and AResponseInfo objects (they are freed when the
event handler exits), so you will have to copy whatever ARequestInfo
data you need, and you will have to manually write the entire HTTP
response headers and body directly to the TIdContext socket.

There are also some risks. If the client disconnects, the TIdContext
object and its socket will be destroyed while your thread is still
running, which can cause your thread to crash. And by unblocking
TIdHTTPServer, the client is also free to send a new request to the
server while your thread is still processing a previous request. This
might not be a bad thing, actually, as it would allow you to implement
HTTP pipelining, for instance (provided you serialize your
asynchronous responses so they get sent to the client in the right
order).

Trying to help my android client I have added this:

AResponseInfo.ContentText := CreateJSONResult('result',
'0').AsString;
AResponseInfo.WriteHeader;
AResponseInfo.WriteContent;
In an attepmt to free the client from waiting longer.
That will free up the client, but it will not free up the server. And
you will not be able to send any further responses to the client, if
you have more data to send.

However the client makes a new request too soon while the previous
thread remains working.
Exactly. The client does not know what the server is doing. If you
make the server run asynchronously, there is nothing you can do to
prevent the client from sending a new request.

There is a process of login on my server, it is not stateless, so I
need to have the thread finished to accept a new request, unless I
detach it from the thread.
You need to track state information and have your event handler act
according to the current state. You can put state information in your
TyClientContext class, or you can use TIdHTTPServer's built-in session
management (which requires the client to support cookies).
TIdHTTPServer has OnCreateSession, OnSessionStart and OnSessionEnd
events, and the ARequestInfo and AResponseInfo objects have a Session
property. You can use the TIdHTTPSession.Content property to store
state information. Just make sure the TIdHTTPServer.SessionState
property is True, and the TIdHTTPServer.SessionIDCookieName property
has a non-blank value assigned.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: idHttp and CreatingAnonymousThread
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 4, 2015 12:52 PM   in response to: Eduardo Elias in response to: Eduardo Elias
Eduardo wrote:

My server recently started to sometimes consume 99% of the cpu.

That means you have a thread that is not yielding to the CPU.

Is there any of the idHttpServer properties that I am using as default
that could be causing this?

No. It has to be something you are doing (or not doing) in your event handlers
to let Indy yield to the CPU periodically. What does TyClientContext.HandleRequest()
actually look like?

--
Remy Lebeau (TeamB)
Eduardo Elias

Posts: 319
Registered: 9/20/12
Re: idHttp and CreatingAnonymousThread
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 5, 2015 3:29 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Hello Remy,

my handlerequest is just a pathway to a universe of things... as below

<code>
procedure TyClientContext.HandleRequest(ARequestInfo: TIdHTTPRequestInfo;
AResponseInfo: TIdHTTPResponseInfo);
var
IndexApp: integer;

begin
Log('', true);
Log('Nova Conexao
'+DateTimeToStr(now), true);
Log('>> IP ['+Binding.PeerIP+'] Porta ['+IntToStr(Binding.PeerPort)+']',
true);
Log(ARequestInfo.Params.Text, true);

IndexApp := yActivity.CheckToken(ARequestInfo.Params.Values['token']);
// test if token was given by the server at login process
if IndexApp < 0 then // there is no token, create a new activity
begin
IndexApp := yActivity.CreateNewActivity(ARequestInfo); // the activity
object is created and stored in a global list
if IndexApp < 0 then // if creation was ok answer with ok
AResponseInfo.ContentText := CreateJSONResult('result', IntToStr(IndexApp)).AsString;
end;

if IndexApp >= 0 then // otherwise the request is valid and there is an
activity object already created to be used for the request
if not yLicenses.BlockConnections then
begin
// here is the main processing, according to the IndexApp it will call
a specif request passing down aRequestInfo and AResponseInfo
Case yActivity.CallActivity(IndexApp, self, ARequestInfo, AResponseInfo)
of
0 : ; // nothing to do. Result is already in ContextText
-1 : ; // nothing to do. Protect against loop
else
AResponseInfo.ContentText := CreateJSONResult('result', '-1').AsString;
End;
end
else
begin
AResponseInfo.ContentText := CreateJSONResult('result', '-5').AsString;
end;

//Log(AResponseInfo.ContentText, true);

Signal(1); // update traffic
end;

<code>

Interesting is that was already working for at least 2 years, never had happened
this 99% cpu thing.

Since I previously login each client, I create a TList<TActivity> that is
global to the application. This is where I hold all the context.

when HandleRequest arrives basically I lookup for the proper activity object
in the TList and use it. There are many HandleRequest specific to each request
asked, so the client as for "getitem" then I have a

procedure GetItem(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo;
var AResponseInfo: TIdHTTPResponseInfo);

I implement this for example:

<code>
procedure TActivityZX.GetItem(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo;
var AResponseInfo: TIdHTTPResponseInfo);
var
MemTable : Tdxmemdata;
Estab : integer;
FKey : string;
JSON : ISuperObject;
item : longint;
begin
try
FKey := ARequestInfo.Params.Values['key'];
Estab := StrToIntDef(ARequestInfo.Params.Values['estab'], 1);

item := GetItemCodigo(fkey);
if item = 0 then
item := StrToIntDef(fkey, 0);

MemTable := GetDXMemTable;

if not yashar.wsrequests.zx.int.GetItems(LocalDatabase, DSQuery, item,
MemTable) then
begin
AResponseInfo.ContentText := CreateJSONResult('result', '1').AsString;
exit;
end;

JSON := CreateJSONResult('result', '0');
JSON.O['table'] := DataSetToJson(MemTable, 'item');
AResponseInfo.ContentText := JSON.AsString;

finally
MemTable.Free;
CloseDatabase;
end;

end;

<code>

Where I lookup for a Item on the Item Table. As you see I create and delete
everything that is needed locally. Since is a thread the database is isolated
by thread. Actually this code is one of the oldest and always worked fine,
and asking for item is the simplest one either.

There are some cases where many database interactions are happening that
takes 3 ..5 seconds in total to be completed. In few cases I already send
a status back to the client so it does not keep waiting anymore (sure there
is no need for any other data, just processing completion)

yesterday, after many changes I have not experienced this problem anymore,
however I am exposing here the method I am using because your opinion is
of much value.

my major problem remains with one specific device that I need to communicate
at the very end of the process of requests. It is a thermal printer that
print fiscal cupom. It has a specific protocol and I am using thrid party
library that communicats by serial port to handle it.

After some time I lost control completelly of the interatction with this
device, and sometimes even the windows serial driver gets busy to a point
that only restarting the computer to keep going.

I know can many things, however based on past experiences with this hardware
and library it seems to be more related to the fact I am using it from the
thread.

THanks for any insight in any of the problems.

Eduardo

Eduardo wrote:

My server recently started to sometimes consume 99% of the cpu.
That means you have a thread that is not yielding to the CPU.

Is there any of the idHttpServer properties that I am using as
default that could be causing this?
No. It has to be something you are doing (or not doing) in your event
handlers to let Indy yield to the CPU periodically. What does
TyClientContext.HandleRequest() actually look like?
Eduardo Elias

Posts: 319
Registered: 9/20/12
Re: idHttp and CreatingAnonymousThread
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 12, 2015 8:56 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Hello Remy,

Based in this project below I am experiencing another strange problem, do
you mind in give a direction?

This software is a Rest Server used by tablets in a POS system. The restaurant
has 2 Tablet as POS Cashiers, 4 tablets used by garcons

the Client software is based on java, and it makes request for each situation,
open a table, insert new item on the table, print the receipt, etc.

The inteligence of the project is in the rest server. When the request is
made to the server, it comes with some other information so I can select
the proper procedure, do whaterver is necessary and answer to the client.

Commonly the answer is almost imediatly

There are database operation, each time the request arrive I create the connection
(right now is based on DBISAM) and the tablets necessary, at end i disconnect
and free everything.

I make sure the server start fresh everyday, however when there are the peak
of customers in the restaurant the software response degrates a lot.

Most of the time a simple table requisition take 1 second since the send
of the request until showing it on the tablet screen. It is pretty fast.

However what is strange is that the number os request are greater but it
is very hard to see concurrency. From the server standpoint this increase
of work was supposed to be nothing.

The only more complicated operation is when a payment is made and it changes
around 6 tables, in a normal condition it requires 2 seconds for the answer.

Said that, it seems that it is nothing (apparently) on the requests, since
they mantain the same answer time.

There is also protection over recurrency based on a simple semaphore implemented
with a global critical section.

      SetInUse(true);
      try
        Activity.Items[idx].QueryService(AContext, ARequestInfo, AResponseInfo);
      finally
        SetInUse(false);
      end;


where:

  procedure SetInUse(aInUse: boolean);
  begin
    EnterCriticalSection(GlobalSection);
    try
      Activity.Items[idx].InUse := aInUse;
    finally
      LeaveCriticalSection(GlobalSection);
    end;
  end;


My clients are required to do a login in the server in order to get configuration
and check licensing, after that they get a token that is used to access the
context object from a TList.

The request are mostly stateless, very few information remains in the context
object.

I am experimenting is a overwall slowliness in the server. The CPU indicator
remains with IDLE 99% of the time. So there is no loop inside the server
apparently

It is just when more work is required things start to slow down... the database
that is increased is an orders table that is small and should not be a problem
at all.

I see the client doing the request, and looking at the server LOG there is
a delay before it gets the request on my HandleRequest:

procedure TyClientContext.HandleRequest(ARequestInfo: TIdHTTPRequestInfo; 
AResponseInfo: TIdHTTPResponseInfo);
var
  IndexApp: integer;
 
begin
  Log('', true);
  Log('Nova Conexao ------------------------- '+DateTimeToStr(now), true);
  Log('>> IP ['+Binding.PeerIP+'] Porta ['+IntToStr(Binding.PeerPort)+']', 
true);
  Log(ARequestInfo.Params.Text, true);
 
  IndexApp := yActivity.CheckToken(ARequestInfo.Params.Values['token']); 
// test if token was given by the server at login process
  if IndexApp < 0 then // there is no token, create a new activity
  begin
    IndexApp := yActivity.CreateNewActivity(ARequestInfo); // the activity 
object is created and stored in a global list
    if IndexApp < 0 then // if creation was ok answer with ok
      AResponseInfo.ContentText := CreateJSONResult('result', IntToStr(IndexApp)).AsString;
  end;
 
  if IndexApp >= 0 then // otherwise the request is valid and there is an 
activity object already created to be used for the request
    if not yLicenses.BlockConnections then
    begin
      // here is the main processing, according to the IndexApp it will call 
a specif request passing down aRequestInfo and AResponseInfo
      Case yActivity.CallActivity(IndexApp, self, ARequestInfo, AResponseInfo) 
of
        0   : ; // nothing to do. Result is already in ContextText
        -1  : ; // nothing to do. Protect against loop
      else
        AResponseInfo.ContentText := CreateJSONResult('result', '-1').AsString;
      End;
    end
    else
    begin
      AResponseInfo.ContentText := CreateJSONResult('result', '-5').AsString;
    end;
 
  //Log(AResponseInfo.ContentText, true);
 
  Signal(1); // update traffic
end;


I do not undestand what could be holding the request and slowing down the
overall performance. I should be capable of doing that, the computer is a
I3 running windows 2008 server with 4gig ram, with nothing else running.

Thanks for any advise. This is now causing me a lot of trouble with a big
customer and I have no idea how to solve this one.

Eduardo


Eduardo wrote:

My question is if I could use CreateAnonymousThread to "detach" my
code, from inside the idHttp thread.
Like everything else in Indy, TIdHTTPServer's processing of client
requests is designed to be synchronous. By default, when you exit
from your OnCommandGet event handler, TIdHTTPServer will send a
reponse to the client. You are expected to populate the AResponseInfo
with your final response data before exiting the event handler.

That being said, there is one way to do what you are asking for.

Set TIdHTTPServer.KeepAlive to true, and then have your event handler
set AResponseInfo.HeaderHasBeenWritten to True,
AResponseInfo.CloseConnection to False, AResponseInfo.ContentText to a
blank string, and AResponseInfo.ContentStream to nil. This way,
TIdHTTPServer will not automatically send a response to the client, or
close the socket connection, when the event handler exits.

Now, you can have your event handler launch a worker thread to process
the request asynchronously as needed. However, you will lose access
to the ARequestInfo and AResponseInfo objects (they are freed when the
event handler exits), so you will have to copy whatever ARequestInfo
data you need, and you will have to manually write the entire HTTP
response headers and body directly to the TIdContext socket.

There are also some risks. If the client disconnects, the TIdContext
object and its socket will be destroyed while your thread is still
running, which can cause your thread to crash. And by unblocking
TIdHTTPServer, the client is also free to send a new request to the
server while your thread is still processing a previous request. This
might not be a bad thing, actually, as it would allow you to implement
HTTP pipelining, for instance (provided you serialize your
asynchronous responses so they get sent to the client in the right
order).

Trying to help my android client I have added this:

AResponseInfo.ContentText := CreateJSONResult('result',
'0').AsString;
AResponseInfo.WriteHeader;
AResponseInfo.WriteContent;
In an attepmt to free the client from waiting longer.
That will free up the client, but it will not free up the server. And
you will not be able to send any further responses to the client, if
you have more data to send.

However the client makes a new request too soon while the previous
thread remains working.
Exactly. The client does not know what the server is doing. If you
make the server run asynchronously, there is nothing you can do to
prevent the client from sending a new request.

There is a process of login on my server, it is not stateless, so I
need to have the thread finished to accept a new request, unless I
detach it from the thread.
You need to track state information and have your event handler act
according to the current state. You can put state information in your
TyClientContext class, or you can use TIdHTTPServer's built-in session
management (which requires the client to support cookies).
TIdHTTPServer has OnCreateSession, OnSessionStart and OnSessionEnd
events, and the ARequestInfo and AResponseInfo objects have a Session
property. You can use the TIdHTTPSession.Content property to store
state information. Just make sure the TIdHTTPServer.SessionState
property is True, and the TIdHTTPServer.SessionIDCookieName property
has a non-blank value assigned.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: idHttp and CreatingAnonymousThread
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 13, 2015 12:01 PM   in response to: Eduardo Elias in response to: Eduardo Elias
Eduardo wrote:

Based in this project below I am experiencing another strange problem,
do you mind in give a direction?

Are you sure your database code is thread-safe to begin with? What about
your activity code? Your logging code?

Since you are having problems under heavier load, maybe you are serializing
access to things that don't need to be serialized? Hard to say for sure
without knowing what your code is actually doing.

Also, you say you are connecting to, and disconnecting from, the database
on every request. Have you tried using a connection pool instead so you
can stay connected to the database in between requests? Creating a new connection
each time has significant overhead. You should disconnect a database connection
only when it is truely idle, when it has not been used for awhile. You should
reuse existing connections when possible. Create a pool of connections,
and each time a new request arrives, grab a connection from the pool, use
it as needed, and then put it back into the pool so another request can use
it. Or, since you are using an Indy server, you can assign a TIdSchedulerOfThreadPool
to the server, and derive a custom class from TIdThreadWithTask and give
that class its own dedicated database connection, then assign that class
to the scheduler. Inside your requst haandler, you can access the database
connection of whichever thread is currently servicing the request.

There is also protection over recurrency based on a simple semaphore
implemented with a global critical section.

That alone does not necessary guarantee that the code is thread-safe, though.

My clients are required to do a login in the server in order to get
configuration and check licensing, after that they get a token that is
used to access the context object from a TList.

Why are you managing your own TList? Are you protecting it?

IndexApp := yActivity.CheckToken(ARequestInfo.Params.Values['token']);
// test if token was given by the server at login process
if IndexApp < 0 then // there is no token, create a new activity
begin
IndexApp := yActivity.CreateNewActivity(ARequestInfo); // the
activity object is created and stored in a global list

What does IndexApp actually represent? Its name suggests it is an index
in the global list. That would be VERY bad. What is to stop another client/thread
from removing activities from the list while the current request is being
processed? That removal would change the index value of every activity object
that happens to follow the removed object in the list. In between CheckToken()
and CallActivity(), the index of the current activity might change. Relying
on a list index in this manner is very dangerous. I would suggest having
CheckToken()/CreateNewActivity() return the actual activity object, and then
pass that object to CallActivity() (or change CallActivity() to be a method
of the activity class itself).

--
Remy Lebeau (TeamB)
Eduardo Elias

Posts: 319
Registered: 9/20/12
Re: idHttp and CreatingAnonymousThread
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 13, 2015 3:56 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Hello Remy,

Thanks for you answer, following my comments:

Eduardo wrote:

Based in this project below I am experiencing another strange
problem, do you mind in give a direction?
Are you sure your database code is thread-safe to begin with? What
about your activity code? Your logging code?

I believe is thread-safe, I followed the guidelines of the vendor (elevatesoft)
for it, and already used this way in the past with no trouble. So, I create
everything in the thread isolated from any other thread, specially the session
object that is not global.

for logging I use a class derived from TIdNotify that I followed and example,
I do not "contact" anything from the main thread unless thru TyLog.DoNotify;

My activity code only uses local variables, or the values from the http request.
Otherwise it deals with the database.


Since you are having problems under heavier load, maybe you are
serializing access to things that don't need to be serialized? Hard
to say for sure without knowing what your code is actually doing.

I know it is hard to say something on this, however I am exposing to eventually
find an idea.

I could have doubt of my code in some cases, however simple read order from
the database is taking longer, and that is very simple query function, since
I am using DBISAM in this case, I am using their server, instead of using
direct table access, what teoretically would reduce threading issues, since
the file access is in the server side.


Also, you say you are connecting to, and disconnecting from, the
database on every request. Have you tried using a connection pool
instead so you can stay connected to the database in between requests?
Creating a new connection each time has significant overhead. You
should disconnect a database connection only when it is truely idle,
when it has not been used for awhile. You should reuse existing
connections when possible. Create a pool of connections, and each
time a new request arrives, grab a connection from the pool, use it as
needed, and then put it back into the pool so another request can use
it. Or, since you are using an Indy server, you can assign a
TIdSchedulerOfThreadPool to the server, and derive a custom class from
TIdThreadWithTask and give that class its own dedicated database
connection, then assign that class to the scheduler. Inside your
requst haandler, you can access the database connection of whichever
thread is currently servicing the request.

that is something to consider, however, the problem is that a request that
is supposed to take 2 seconds (all small tables, simple queries etc) are
taking 5 seconds. And I only can see most of the time only one connection.
This is not a busy http server with hundreds of connections. That is my major
concern, even that my code is not optmized, most of the time it can take
only 2 seconds to answer, that is just fine. But in some situation is getting
3 times more for no reason.


There is also protection over recurrency based on a simple semaphore
implemented with a global critical section.
That alone does not necessary guarantee that the code is thread-safe,
though.

Yes, but at least guarantee that if a timeout happens in the client side
and it comes again for another request I can stop it. But based on the log
I am not having this issue.


My clients are required to do a login in the server in order to get
configuration and check licensing, after that they get a token that
is used to access the context object from a TList.
Why are you managing your own TList? Are you protecting it?

Not sure how protection applies here.

This TList is an "Activity" list, that is, according to the application from
the client I create the proper object that will be added to the TList.

IT IS NEVER DELETED EVER, so it will have the number of clients connected
on the network to this server, that right now could be from 1 to 10, I dont
have anyone using it with more than 10 connections. Each activity is based
on the serial number of the android client, so it is limited to the number
of clients, that is always low, considering what can be done in a Http server


IndexApp :=
yActivity.CheckToken(ARequestInfo.Params.Values['token']);
// test if token was given by the server at login process
if IndexApp < 0 then // there is no token, create a new activity
begin
IndexApp := yActivity.CreateNewActivity(ARequestInfo); // the
activity object is created and stored in a global list
What does IndexApp actually represent? Its name suggests it is an
index in the global list. That would be VERY bad. What is to stop
another client/thread from removing activities from the list while the
current request is being processed? That removal would change the
index value of every activity object that happens to follow the
removed object in the list. In between CheckToken() and
CallActivity(), the index of the current activity might change.
Relying on a list index in this manner is very dangerous. I would
suggest having CheckToken()/CreateNewActivity() return the actual
activity object, and then pass that object to CallActivity() (or
change CallActivity() to be a method of the activity class itself).

I might be wrong, however considering that IndexApp is a local variable in
a thread, its value remains the same, so I think you are considering the
case of the TList<Activity> getting changed, and that never happens. This
list only increse, at moment each new client login.

Based on my log, it seems that the request is hold BEFORE get on this activity
selection. Even before HandleRequest is called.

I have my first log info at first line of HandleRequest, and when it happens
it does all the work and respong the request just quick it should be. There
is no additional time between the start and the end of the request processing.

The problem is before reaching my code.

So could it be there something in the Indy protocol that i am not configuring
right?

I have found today this: http://forum.tp-link.com/showthread.php?81542-WR841HP(HG)-ARP-Delay&p=162999#post162999

This guy is using exactly the same router/wifi that I am using, and he says
he suffer of a delay, up to 5 seconds in many situations, thing that he was
not having with another router with the same devices.

I am not aware of low level network protocol to validate this situation,
he says about arp packets that are not anwered or are lost by the router.

It seems similar to the problem I am experiencing, unless there is something
else on Indy that I am not doing right.

Thank you Remy, appreciate your time.

Eduardo Elias

Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: idHttp and CreatingAnonymousThread
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 13, 2015 5:49 PM   in response to: Eduardo Elias in response to: Eduardo Elias
Eduardo wrote:

that is something to consider, however, the problem is that a request
that is supposed to take 2 seconds (all small tables, simple queries
etc) are taking 5 seconds. And I only can see most of the time only
one connection. This is not a busy http server with hundreds of
connections. That is my major concern, even that my code is not
optmized, most of the time it can take only 2 seconds to answer, that
is just fine. But in some situation is getting 3 times more for no
reason.

Then you need to profile your code, such as with AQTime, to find out where
it is actually spending its time.

Why are you managing your own TList? Are you protecting it?
Not sure how protection applies here.

This TList is an "Activity" list, that is, according to the application
from
the client I create the proper object that will be added to the TList.

You are sharing a global TList across multiple threads. Each client connection
runs in its own thread. HTTP requests may use multiple connections, even
from the same client, depending on whether HTTP keep-alives are being used
or not. So, access to the listmust be protected.

I might be wrong, however considering that IndexApp is a local variable
in a thread, its value remains the same

The variable itself is local, but the value it holds represents something
in a global list.

so I think you are considering the case of the TList<Activity> getting
changed, and that never happens. This list only increse, at moment each
new client login.

OK. But you still have to protect the list in case multiple clients try
to add new activities at the exact same time.

Based on my log, it seems that the request is hold BEFORE get on this
activity selection. Even before HandleRequest is called.

Then please show your actual log. I assume it has timestamps in it. Do
the timestamps represent when Log() is entered, or when DoNotify() is called?

The problem is before reaching my code.

But how do you know that? What are you actually looking at that says there
is a delay occuring? Are you logging anything about the incoming request
before it reaches HandleRequest()? Have you sniffed the network to watch
the request being sent from the client and responded to by the server in
real-time? Maybe the client is not sending requests as fast as you think
they are. Maybe your network is delaying the packets between endpoints.
Who knows. There are so many factors that could be causing delays. You
need to stop guessing and start investigating.

So could it be there something in the Indy protocol that i am not
configuring right?

Doubtful.

I have found today this:
http://forum.tp-link.com/showthread.php?81542-WR841HP(HG)-ARP-Delay&p=162999#post162999

This guy is using exactly the same router/wifi that I am using, and he
says he suffer of a delay, up to 5 seconds in many situations, thing
that he was not having with another router with the same devices.

A log from a network sniffer would show you if that were actually happening
on your network or not.

--
Remy Lebeau (TeamB)
Eduardo Elias

Posts: 319
Registered: 9/20/12
Re: idHttp and CreatingAnonymousThread
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 15, 2015 6:43 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Hello Remy,

I have found the reason of this problem:

The router I was using (Tp-Link) has a bug in its software and was interfering
with HTTP requests, delaying it 5 to 10 seconds.

This is the reason I saw the request getting out from the tablet and not
reaching my code.

When I changed the router the problem vanished.

Anyways, all information you provided helped get the code better.

Thanks

Eduardo

Eduardo wrote:

that is something to consider, however, the problem is that a request
that is supposed to take 2 seconds (all small tables, simple queries
etc) are taking 5 seconds. And I only can see most of the time only
one connection. This is not a busy http server with hundreds of
connections. That is my major concern, even that my code is not
optmized, most of the time it can take only 2 seconds to answer, that
is just fine. But in some situation is getting 3 times more for no
reason.
Then you need to profile your code, such as with AQTime, to find out
where it is actually spending its time.

Why are you managing your own TList? Are you protecting it?
Not sure how protection applies here.

This TList is an "Activity" list, that is, according to the
application
from

the client I create the proper object that will be added to the
TList.
You are sharing a global TList across multiple threads. Each client
connection runs in its own thread. HTTP requests may use multiple
connections, even from the same client, depending on whether HTTP
keep-alives are being used or not. So, access to the listmust be
protected.

I might be wrong, however considering that IndexApp is a local
variable in a thread, its value remains the same
The variable itself is local, but the value it holds represents
something in a global list.

so I think you are considering the case of the TList<Activity>
getting changed, and that never happens. This list only increse, at
moment each new client login.
OK. But you still have to protect the list in case multiple clients
try to add new activities at the exact same time.

Based on my log, it seems that the request is hold BEFORE get on this
activity selection. Even before HandleRequest is called.
Then please show your actual log. I assume it has timestamps in it.
Do the timestamps represent when Log() is entered, or when DoNotify()
is called?

The problem is before reaching my code.
But how do you know that? What are you actually looking at that says
there
is a delay occuring? Are you logging anything about the incoming
request
before it reaches HandleRequest()? Have you sniffed the network to
watch
the request being sent from the client and responded to by the server
in
real-time? Maybe the client is not sending requests as fast as you
think
they are. Maybe your network is delaying the packets between
endpoints.
Who knows. There are so many factors that could be causing delays.
You
need to stop guessing and start investigating.
So could it be there something in the Indy protocol that i am not
configuring right?
Doubtful.

I have found today this:
http://forum.tp-link.com/showthread.php?81542-WR841HP(HG)-ARP-Delay&p
=162999#post162999
This guy is using exactly the same router/wifi that I am using, and
he says he suffer of a delay, up to 5 seconds in many situations,
thing that he was not having with another router with the same
devices.
A log from a network sniffer would show you if that were actually
happening on your network or not.
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02