tags:

views:

298

answers:

6

Hi all,

My first question here.

The question is similar to this one: http://stackoverflow.com/questions/712161/php-retrying-a-query-a-set-number-of-times-or-until-success

Try till success in OO way. Here example what i'm trying to do:

class Creatives {

public function run() {
 $auth_token='mypassword';
 $id=123123;
 $this->retry_till_success ( $this->getCreatives, array($auth_token, $id) );
 print $this->creatives; 
}

public function getCreatives($auth_token, $id) {
 $this->creatives = $this->campagin->get($auth_token, $id);  
}

private function retry_till_success($method, $args) {
 do {
  $try_again = false;
  try {
   /* how to call the method with */
   /* call user method with params pass */
   /* do until success */
  } catch (SoapFault $fault) {
   if($fault->faultstring== 'couldnt connect to host')
    $try_again=true;
  }
 } while ($try_again);
}

}

i read about call_user_func, but don't know if i could use it inside the class, I need to make 99.9% success rate in my calls, any suggestion to achieve this will be great. thank you.

A: 
private function retry_till_success($method, $args) {

...

$this->$method($args[0], $args[1]);

}

You could also use ReflectionClass/ReflectionMethod and call InvokeArgs() for a variable number of args

http://nz.php.net/oop5.reflection

David Archer
thanks but this should be generic numbers of arguments
stac
what about separating the args inside the function being called? or is the function generic too?
David Archer
I need to implement retry_till_success(any_method, array(args1, args2, ...))accept any method with any number of args to execute it till success.
stac
A: 

call_user_func_array() is great for this:

$result = call_user_func_array( array($this, $method), $args );

The first argument is the callback pseudo-type, and the second is an array of parameters which will be passed to the function/method as individual arguments.

As a side note, you might want to look at throttling your retries (e.g. have a sleep time which doubles every time it fails up to a set limit). If the connection to the host is down there may not be much point in retrying as fast as possible.

Tom Haigh
A: 

I'm not quite sure what you mean, but this is how call_user_func(_array)() works:

call_user_func($method, $arg); //call global function named $method like this: $method($arg)
call_user_func(array($this, $method), $arg); call class method on this class like this: $this->$method($arg);
//lets presume args is an array: $args = array(1, 2);
call_user_func_array($method, $args); //calls global function named $method like this: $method($args[0], $args[1]);
call_user_func_array(array($this, $method), $args); //calls class method like this: $this->$method($args[0], $args[1]);

Also see the documentation for call_user_func:
http://nl3.php.net/manual/en/function.call-user-func.php
and for call_user_func_array:
http://nl3.php.net/manual/en/function.call-user-func-array.php

Pim Jager
A: 

$this->getCreatives won't work because in PHP functions are not base class citizen. You can use call_user_func[_array] or create a factory for tasks and represent every task as an object which implements an interface (ie iRepeatableTask). Thus you can call

try
{    
    $task->repeatUntilSuccess()
} catch (SoapFault $e) {...}

and the advantage is that those objecs are easy-to-save/restore in DB to perform later (ie with cronjob etc.).

Jet
+1  A: 

Best way would be to extend SoapClient and add the retry in the __call method.

class LocalSoapClient extends SoapClient
{

  public function __call($function_name, $arguments)
  {
    $result = false;
    $max_retries = 5;
    $retry_count = 0;

    while(! $result && $retry_count < $max_retries)
    {
      try
      {
        $result = parent::__call($function_name, $arguments);
      }
      catch(SoapFault $fault)
      {
        if($fault->faultstring != 'Could not connect to host')
        {
          throw $fault;
        }
      }
      sleep(1);
      $retry_count ++;
    }
    if($retry_count == $max_retries)
    {
      throw new SoapFault('Could not connect to host after 5 attempts');
    }
    return $result;
  }
}

then when you instantiate your soap client use new LocalSoapClient() instead of new SoapClient()

KRavEN
A: 

Hi All,

Here is my final solution I'm using in production.

    protected function retry_till_success($method, $args) {
 /*
 * -1 : unrecoverable error
 *   0 : recoverable error
 *   1 : success
 */
 $success = 0;
 $tries = 0;

 do {
  $tries++;
  $success = call_user_func_array( array($this, $method), $args );
  if ($success===0) {
   usleep(self::DELAY_MS);
  }
 } while ($success===0 && $tries < self::MAX_RETRIES);

 if ($tries >= self::MAX_RETRIES)
  return false;

 return true;
}
stac