Re: Callback to delay a Server::TCP component?

"[email protected]" <[email protected]> Mon, 19 Apr 2010 00:38:41 -0700
Newsgroups gmane.comp.lang.perl.poe
Message-ID <[email protected]>
Ahh, thanks for clarifying this! Yeah, I agree that using 
run_one_timeslice() is a path to insanity, ha!

What I would recommend is the "tried and true" method of... buffering 
the request? The server simply sends the request to the "forwarder" tcp 
session
and it just stores the request in it's heap and when it's connected, it 
gets the request and does it's stuff? You can always create new 
InlineStates in
the PoCo::Client::TCP session and use it to queue up requests.

Pseudocode:

server tcp session:
    client connects, sends request
    spawn forwarder session
    send request to forwarder session -> event "queue_request"

forwarder session:
    event "queue_request" receives requests and stores it in an array in 
the heap
    on connect, retrieve requests from queue and send them
    event "queue_request" now changes behavior and does not store 
requests in the array - it's connected so it immediately does a put()
    if it fails to connect, get request from queue and reply back to 
server with an error

Hope this makes sense and is the right concept now :)

P.S. This kind of design pattern is exactly what Rocco is trying to 
simplify with "Reflex" - you should check out his great work on it!

~Apocalypse

Mike Schilli wrote:
> On Sun, 18 Apr 2010, [email protected] wrote:
>
>>   This is a problem that we've thought of and solved. See the
>>   "Concurrency" option to PoCo::Server::TCP
>
> I should have been more clear. In my case, the server has already
> accepted the client connection, but needs to hold off on forwarding the
> request to the forwarding port until PoCo::Client::TCP has established
> the outgoing connection.
>
> I've reworked the code to use a heap variable instead of a global, and
> all of a sudden it doesn't look so bad now:
>
>     ###########################################
>     sub client_request {
>     ###########################################
>       my ($kernel, $heap, $request) =
>          @_[ KERNEL, HEAP, ARG0 ];
>
>       INFO "Waiting for turn ...";
>       $kernel->run_one_timeslice() while
>         ! $heap->{client_heap}->{connected};
>
>       INFO "Done waiting.";
>
>       $heap->{client_heap}->
>              {server}->put( $request );
>     }
>
> Only remaining ugliness is the run_one_timeslice(), which I'm not a big
> fan of, as it makes it harder to follow the event flow.
>
> Coming back to my original question, which is not really related to
> PoCo::Server/Client::TCP specifically, but to POE in general: If
> a component offers a callback, the approved/best way to 'wait' for an
> event within the callback seems to be run_one_timeslice()?
>
> Too bad the callback is a syncronous call and not an event and therefore
> I can't say "erm, I'm not ready for this callback yet, come back after
> two seconds" unless the component implements this explicitly.
>
> -- Mike
>
> Mike Schilli
> [email protected]
>
>>   
>> http://search.cpan.org/~rcaputo/POE-1.289/lib/POE/Component/Server/TCP.pm#Concurrency 
>>
>>
>>   You must have missed that part or the docs wasn't clear. If you 
>> have suggestions on how to make it more clearer - please let us know!
>>
>>   Happy hacking! :)
>>
>> ~Apocalypse
>>
>> Mike Schilli wrote:
>>> Hi POE folks,
>>>
>>> while writing a port forwarder similar to the one in the POE cookbook,
>>> just by using POE::Component::Server::TCP and ::Client::TCP instead, 
>>> I hit
>>> a roadblock when it came to synchronizing the components.
>>>
>>> After POE::Component::Server::TCP has started up (binding to the 'From'
>>> port), if a client connects to it, the server will call the
>>> client_connect callback, which I'm using to spawn an instance of
>>> POE::Component::Client::TCP to connect to the 'To' port.
>>>
>>> At this time, I need the server to wait accepting requests from the
>>> connecting client *until* POE::Component::Client::TCP has connected 
>>> to the
>>> 'To' port.
>>>
>>> However, there's no way to say in the client_connect callback that the
>>> server should not proceed to the 'client_request' stage yet.
>>>
>>> I found a workaround by setting a global variable $CONNECTED in
>>>
>>>   my $client_session =
>>>     POE::Component::Client::TCP->new(
>>>         # ...
>>>         Connected => sub { $CONNECTED = 1; },
>>>         # ...
>>>
>>> and adding
>>>
>>>   $kernel->run_one_timeslice() while !$CONNECTED;
>>>
>>> to the client_request callback of the POE::Component::Server::TCP
>>> server. This does the trick, but I don't like that it's a
>>> global variable that allows only single use of this component.
>>>
>>> Is there a better way?
>>>
>>> -- Mike
>>>
>>> Mike Schilli
>>> [email protected]
>>