1

In my Catalyst app I have a very important connection to a remote server using SOAP with WSDL.

Everything works fine, but when the remote server goes down due to any reason, ALL my app waits until the timeout expires. EVERYTHING. ALL the controllers and processes, ALL the clients!!

If I set a 15 secs timeout for the SOAP LITE transport error, everything waits for 15 secs. Any page from any user or connection can't be displayed during the timeout wait.

I use Fast CGI and Ngnix for the Catalyst app. If I use multiple fcgi processes when one waits, others take care of the connections, but if all of them try to access the faulty SOAP service... they all wait and wait for an answer until they reach their timeouts. When all of them are waiting, no more connections are allowed.

Looking for answers I have read somewhere that SOAP::LITE is "single threaded".

Is it true? Does it means that ALL my app, with ALL the visitors can only use one SOAP connection? It is hard to believe.

This is my code for the call:

sub check_result {
    my ($self, $code, $IP, $PORT) = @_;

    my $soap = SOAP::Lite->new( proxy => "http://$IP:$PORT/REMOTE_SOAP
+");

    $soap->autotype(0);
    $soap->default_ns('http://REMOTENAMESPACE/namespace/default');
    $soap->transport->timeout(15);

     $soap-> on_fault(sub { my($soap, $res) = @_; 
        eval { die ref $res ? $res->faultstring : $soap->transport->st
+atus };
          return ref $res ? $res : new SOAP::SOM;
       });

     my $som = $soap->call("remote_function",
         SOAP::Data->name( 'Entry1' )->value( $code ),
     );

    return $som->paramsout;
}

I also tried this slightly different approach kindly suggested at perlmonks, but nothing got better

Please, can someone point me in the rigth direction?

Migue

Ferran Buireu
  • 28,630
  • 6
  • 39
  • 67
Nacho B
  • 1,573
  • 1
  • 12
  • 16

1 Answers1

0

This is not a problem with SOAP::Lite or Catalyst per se. Pretty much any resource you query will most likely wait for the return (i.e.: file read on disk, database access). If the resource blocks for a long time, there's a chance that you could "starve" other requests while waiting for this return.

There's not an easy answer to this problem, but you could create a "job queue" that a separate process executes, then instead of calling the other service you would add the entry to the queue and get a token. When the request is finished, the queue stores the result associated with that token, then your app, in a separate request checks if the token you want already has a result or not.

There are specialized "job queue" frameworks, such as RabbitMQ, ApacheMQ and even some solutions on top of Redis. If your web application uses rich Javascript, you could even have the "job queue" notification reach the javascript client using, for instance, WebSockets, but otherwise, just poll every second to see if there is a response or not.

Daniel Ruoso
  • 83,088
  • 1
  • 17
  • 8