views:

501

answers:

5

Salesforce can send up to 100 requests inside 1 SOAP message. While sending this type of Bulk Ooutbound message request my PHP script finishes executing but SF fails to accept the ACK used to clear the message queue on the Salesforce side of things. Looking at the Outbound message log (monitoring) I see all the messages in a pending state with the Delivery Failure Reason "java.net.SocketTimeoutException: Read timed out". If my script has finished execution, why do I get this error?

I have tried these methods to increase the execution time on my server as I have no access on the Salesforce side:

  • set_time_limit(0); // in the script
  • max_execution_time = 360 ; Maximum execution time of each script, in seconds
  • max_input_time = 360 ; Maximum amount of time each script may spend parsing request data
  • memory_limit = 32M ; Maximum amount of memory a script may consume

I used the high settings just for testing.

Any thoughts as to why this is failing the ACK delivery back to Salesforce?

Here is some of the code: This is how I accept and send the ACK file for the imcoming SOAP request

$data = 'php://input';
$content = file_get_contents($data);

if($content) {
    respond('true');
} else {
    respond('false');
}

The respond function

function respond($tf) {
    $ACK = <<<ACK
<?xml version = "1.0" encoding = "utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;
    <soapenv:Body>
        <notifications xmlns="http://soap.sforce.com/2005/09/outbound"&gt;
            <Ack>$tf</Ack>
        </notifications>
    </soapenv:Body>
</soapenv:Envelope>
ACK;

    print trim($ACK); 
}

These are in a generic script that I include into the script that uses the data for a specific workflow. I can process about 25 requests (That are in 1 SOAP response) but once I go over that I get the timeout error in the Salesforce queue. for 50 requests is usually takes my PHP script 86.77 seconds.

Could it be Apache? PHP?

I have also tested just accepting the 100 request SOAP response and just accepting and sending the ACK the queue clears out, so I know it's on my side of things.

I show no errors in the apache log, the script runs fine.

I did find some info on the Salesforce site but still no luck. Here is the link.

Also I'm using the PHP Toolkit 11 (From Salesforce).

Other forum with good SF help

Thanks for any insight into this, --Phill

UPDATE:

If I receive the incoming message and print the response, should this happen first regardless if I do anything else after? Or does it wait for my process to finish and then print the response?

UPDATE #2:

okay I think I have the problem: PHP uses the single thread processing approach and will not send back the ACK file until the thread has completed it's processing. Is there a way to make this a mutli thread process? Thread #1 - accept the incoming SOAP request and send back the ACK Thread #2 - Process the SOAP request

I know I could break it up into like a DB table or flat file, but is there a way to accomplish this without doing that?

I'm going to try to close the socket after the ACK submission and continue the processing, cross my fingers it will work.

A: 

Are you 100% sure that Salesforce will wait the amount of time your scripts need too run? 80 seconds seem like a loong time too me.

If all requests failed I would guess that Salesforce expects you to set the Content-Type header appropriately, but this does not seem to be the case.

middus
I agree 80 seconds does seem long for SF to wait, but I don't know how to increase this time on the SF side of things. You?
Phill Pafford
+1  A: 

Sounds like the outbound message is hitting the timeout. Other users have reported timeouts as low as 10 seconds (see forum link below). The sandbox instance that I use (cs1) is timing out after about 1 minute, from my testing. It's possible that the timeout is an organization or instance level setting that Salesforce controls.

Two things you could try:

  1. Open a support ticket with Salesforce to see if they can increase the timeout value for outbound messages. From my experience, there are lot of settings that they can modify on the organization level - this might be one of them.

  2. Offload processing of your data, so that the ACK is sent immediately back to Salesforce. Then the actual processing of your data will take place asynchronously. ie. Message queue, separate thread, etc.

Some other resources that might be helpful:

related Salesforce forum discussion

Outbound messaging documentation

Adam
Thanks, I do have a ticket open with SF and have posted on several forums about this. The problem is PHP I believe being single threaded process. So regardless of when I send the ACK, it will wait to send it till the process is finished. I have been thinking about splitting up the ACK and the processing into 2 steps but wanted to know if this could all be done in one.
Phill Pafford
+1  A: 

I think they timeout the thing waiting for Your script to end.

There is a way You could try to fix this.

Output the envelope with ack message at the beginning and then flush the thing so that their server gets it before You end processing. No threading, just plain priorities rethinking :)

read this for best info on flushing content

naugtur
I will try this
Phill Pafford
There is one risk - it depends on their implementation, but if it waits for processing to end it might keep waiting evel if You output the whole thing. It might be hackable with sending %00 or some other form of zero value at the end, or by sending a specified end of file.
naugtur
A: 

I don't know about Salesforce, but if you want to make some multithreading with PHP you should take a look at this code example and more precisely to pcntl_fork().

N.B: pcntl is not enabled by default and won't work on Windows platforms.

avetis.kazarian
A: 

So what I've done is:

  1. Accept all incoming OBM's, parse them into a DB
  2. When this is done kick of a process that runs in the background (Actually I send it to the background so the script can end)
  3. Send ACK file back

By just accepting the raw data, parsing into fields and inserting it into a DB is fairly quick. Then I issue a Linux Command Line command that also send the processing script to run in the background. Then I send the ACK file to SF and the script ends within the allotted time. It is cumbersome to split the script process into two separate stages but it works.

Phill Pafford