[fpc-pascal] How to use FCGI in threaded mode?

silvioprog silvioprog at gmail.com
Sat Feb 14 07:18:38 CET 2015


Please excuse me for not answering you before ...

On Wed, Feb 11, 2015 at 4:59 AM, Michael Van Canneyt <michael at freepascal.org
> wrote:
>
> On Tue, 10 Feb 2015, silvioprog wrote:
>>
>>
>> Buddy, I finally could make a draft of a FastCGI application running in
>> multi-thread in proxy mode. =)
>>
>
> Congratulations !!


Thank you! =)


> It worked on:
>>
>> . Windows 7 - 64 bits;
>> . nginx 1.7.9 com o módulo FastCGI distribuído nele;
>> . Apache 24 (httpd-2.4.12-win64-VC11.zip), que já vem com o módulo
>> FastCGI com suporte ao modo proxy;
>> . FPC do trunk.
>>
>> And the steps to test it were:
>>
>> . download and unzip the attached package, after unpacking it, enter the
>> nginx directory and apply its settings in your copy (ainda
>> não testei no Linux, mas farei isso em breve I haven't tested it on
>> Linux yet, but I'll do it soon);
>> . open and run the project1.lpr project;
>> . open a tab in the browser and access http://localhost:81/test?op=loop,
>> it is supposed to be frozen for 10 seconds;
>> . open another tab in the browser and access http://localhost:81/test, it
>> is supposed to show the current time, even with the first
>> tab frozen, this shows that the application is working in multi-thread.
>>
>
> I will test this ASAP :)


Good! =)

Follow attached a unit called mycustfcgi.pp, that is a copy of the trunk
>> custfcgi.pp. I've not created a patch because I believe that
>> it will enter a new class in this unit, probably called TFCGIThread, and
>> it won't be necessary a programmer treat the AcceptConnection
>> method externally and not create extra classes, like "TFastCGIThread" and
>> "TFastCGIRouter" as in the example.
>>
>
> Yes, Ideally, it should be simply a property 'Threaded' in
> TFastCGIApplication.
>
> But, I have looked at the code, and I have several remarks/questions: you
> create threads as requests come in.
>
> This can easily explode. I would prefer an approach where there is a
> thread pool,
> with a size that can be set at startup, or at least a maximum number of
> threads to start.
>
> Do you think you can change the design so it uses a thread pool ?
>

Yes I can, I had thought about a list of threads, but I did without it just
to check how a multi-threaded application behaves in an HTTP server in
proxy mode. =)

In the end implementation, we will have a thread-safe list, so we'll be
able to add a property to limit the maximum number of threads allowed in
the pool. And each item in the pool may also have an extra property
(property Date: Pointer), allowing the programmer to use it to save some
optional information (I plan to use it to save the each user session in the
memory).

Then: you create an instance of the FastCGIHandler for the request, but you
> do not copy the handler's properties (event handlers and so on). How is
> then for example the eventhandler OnIdle called ?
>

That's it. That code was just an example to see the "hello" on the screen,
but the end implementation will have a clone of the request/response in
each thread. =)

I have a question, what is the OnIdle used for? If I got it, it waits for
more requests on the same thread. Is it right?

Watching the following code:

      If (poUseSelect in ProtocolOptions) then
        begin
        While Not DataAvailable do
          If (OnIdle<>Nil) then
            OnIdle(Self);
        end;
...
    until Result or (FHandle=THandle(-1));

It seems that it is triggered when there is no data in the socket. If I'm
right about this, I can create a OnIdle for each socket.

As we are going to change this part of the code, we could create the
DoReadingData and DoWrittingData methods, they could be used to show a
progress of sent and received data to the application. But it can be
implemented later.

Maybe it is better to refactor the code so there is a separate
> 'FastCGIIOHandler' object or something like it.
>

So, If the OnIdle is used to wait for more requests on the same thread, we
could create this class above, and it can be an attribute of the thread,
handled in a loop in the thread, and to catch the OnIdle of triggerred in
each thread, we could create a kind of "listener", that is just another
property in the thread-safe list itself, avoiding thread deadlock.


> Another question.
> As I see it, you create a thread per accepted connection. Each connection
> can handle multiple requests. All requests on a connection are handled
> within the same thread.
>

Yes. I have a micro chat application that I created using my own protocol,
and there I use a thread per request. But it is a structure that I created
by myself, so it could be different from the structure and proposal of
FastCGI. I came up with a question: how can I configure the FastCGI to
accept more than one request per connection? Is it possible in proxy mode?!
I saw the RequestsArray property and it drove me to think that you receive
more than one request per connection.

I need to understand this structure to implement a listener, where each
thread will have its own events and they could be accessed asynchronously.

What about an approach where there is a pool of threads that handles
> requests ?


It will be a perfect approach!

I'll try to do it in the most performative and simple way as possible, then
I'll send each change for you to evaluate, so when it becomes usable, we
could apply it in the trunk. =)

I will also be very careful not to break the compatibility of custfcgi with
legacy applications.

 I believe that with some tips of you, I can make this implementation by
>> myself and then send a patch.
>>
>> It would be great if this feature has already come in FPC 3.0, which is
>> about to be released. =)
>>
>
> We will see, I think this is a big feature, and that is "bad" because big
> merges to fixes branch are not easily accepted.
>

No problems buddy. =)

I'm planning to create an open source library (DLL/SO) to use the FPC
FastCGI layer in other languages (at first in Delphi7 and XE7). I've
already made a draft and it is working perfectly, but I want to make it
multi-threaded, so I can use the FPC by branch fixes, applying my changes
locally, and wait for them to be applied in the official repository.

Anyway: Great work !


Thank you. And I thank you for the great help you are providing me! =)

Pretty soon we'll have a robust structure to use FastCGI in multi-thread
mode ...

-- 
Silvio Clécio
My public projects - github.com/silvioprog
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-pascal/attachments/20150214/c6189c47/attachment.html>


More information about the fpc-pascal mailing list