Skip to content

ConfigurableCallable

headzoo edited this page Apr 2, 2014 · 1 revision

Creates a callable instance with configurable behavior.

Primarily used when you need to continuously call a method or function until certain conditions are met. For example until an exception isn't being thrown, or a specific value is returned.

Examples

In this example you want to insert a row into the database, which may lead to a DeadLockException being thrown. The recommended action for dead locks is retrying the query. We use a ConfigurableCallable instance to keep trying the query until it succeeds.

// Establish a link to the database, and create a callable wrapping the
// mysqli_query() function.
$link  = mysqli_connect("localhost", "my_user", "my_password", "my_db");
$query = new ConfigurableCallable("mysqli_query");

// The retryOnException(DeadLockException:class) call tells $query to keep calling
// mysqli_query($link, "INSERT INTO `members` ('headzoo')") until DeadLockException
// is no longer being thrown. As many times as needed, or until the $query->max_retries
// (defaults to 10) value is reached.
$query->retryOnException(DeadLockException::class);
$result = $query($link, "INSERT INTO `members` ('headzoo')");

In this example we will call a remote web API, which sometimes takes a few tries depending on how busy the remote server is at the any given moment. The remote server may return an empty value (null), the API library may thrown an exception, or PHP may trigger an error.

$api     = new RemoteApi();
$members = new ConfigurableCallable([$api, "getMembers"]);

// When calling retryOnException() without the name of a specified exception,
// the callable will keep retrying when any kind of exception is thrown.
$members->retryOnException()
        ->retryOnError()
        ->retryOnNull();

// The $members instance will keep trying to call $api->getMembers(0, 10) until
// an exception is no longer being thrown, PHP is not triggering any errors,
// and the remote server is not returning null.
$rows = $members(0, 10);

The ConfigurableCallable::setMaxRetries() method is used to limit the number of times before the callable gives up. If the callable does give up, it will return the last value returned by the wrapped function, or throw the last exception thrown by the function. PHP errors are converted to exceptions and thrown. Errors can be logged by passing a psr\Log\LoggerInterface instance to the ConfigurableCallable constructor.

$link  = mysqli_connect("localhost", "my_user", "my_password", "my_db");
$query = new ConfigurableCallable("mysqli_query", new FileLogger());
$query->retryOnException(DeadLockException::class);
$query->setMaxRetries(5);

// The $query instance will throw the last caught DeadLockException if the
// max retries value is reached without successfully inserting the row. 
try {
     $result = $query($link, "INSERT INTO `members` ('headzoo')");
} catch (DeadLockException $e) {
     die("Could not insert row.");
}

There are dozens of different configuration options, which are listed below. In this example we keep calling a function until it returns a value greater than 42. We'll pass -1 to the setMaxRetries() method, which means retry an unlimited number of times.

$counter = ConfigurableCallable::factory(function() {
     static $count = 0;
     return ++$count;
});
$counter->setMaxRetries(-1)
        ->retryOnLessThan(42);
echo $counter();
// Outputs: 42

In addition to the retry conditions, there are also return conditions, and throw conditions. In this example we want to call a remote API until it returns true or false.

$api     = new RemoteApi();
$members = new ConfigurableCallable([$api, "doesMemberExist"]);
$members->returnOnTrue()
        ->returnOnFalse();
$does_exist = $members("headzoo");

::setMaxRetries

Sets the max number of retries.

$counter = ConfigurableCallable::factory(function() {
  static $count = 0;
  return ++$count;
});
$counter->setMaxRetries(-1)
     ->retryOnLessThan(42);
echo $counter();
// Outputs: 42

::setFilter

Sets a return value filter.

$func = ConfigurableCallable::factory(function() {
  return "hello world!";
});
$func->setFilter(function($str) {
  return strtoupper($str);
});
echo $func();

// Outputs: "HELLO WORLD!"

::retryOnException

Retry the function until an exception is not being thrown.

$callable = ConfigurableCallable::factory("myFunction");
// To retry when a specific exception is thrown.
$callable->retryOnException(LogicException::class);
// To retry when any exception is thrown.
$callable->retryOnExcpetion();

$callable();

::returnOnException

Return from the function when an exception is thrown.

$callable = ConfigurableCallable::factory("myFunction");
// To return when a specific exception is thrown.
$callable->returnOnException(LogicException::class);
// To return when any exception is thrown.
$callable->returnOnExcpetion();

$callable();

::throwOnException

Throw any exception thrown by the function.

$callable = ConfigurableCallable::factory("myFunction");
// To re-throw a specific exception.
$callable->throwOnException(LogicException::class);
// To re-throw any exception.
$callable->throwOnException();

$callable();

::retryOnError

Retry the function until no errors are triggered.

$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnError();
$callable();

::returnOnError

Return from the function when an error is triggered.

$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnError();
$callable();

::throwOnError

Throw an exception when the function triggers an error.

$callable = ConfigurableCallable::factory("myFunction");
$callable->throwOnError();
$callable();

::retryOnTrue

Retry the function when it returns true.

$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnTrue();
$callable();

::returnOnTrue

Return from the function when it returns true.

$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnTrue();
$callable();

::retryOnFalse

Retry the function when it returns false.

$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnFalse();
$callable();

::returnOnFalse

Return from the function when it returns false.

$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnFalse();
$callable();

::retryOnNull

Retry the function when it returns null.

$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnNull();
$callable();

::returnOnNull

Return from the function when it returns null.

$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnNull();
$callable();

::retryOnInstanceOf

Retry the function when it returns a specific type of object.

$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnInstanceOf(SomeClass::class);
$callable();

::returnOnInstanceOf

Return from the function when it returns a specific type of object.

$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnInstanceOf(SomeClass::class);
$callable();

::retryOnEquals

Retry the function when the return value equals a specific value.

$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnEquals(42);
$callable();

::returnOnEquals

Return from the function when the return value equals a specific value.

$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnEquals(42);
$callable();

::retryOnNotEquals

Retry the function when the return value does not equal a specific value.

$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnNotEquals(42);
$callable();

::returnOnNotEquals

Return from the function when the return value does not equal a specific value.

$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnNotEquals(42);
$callable();

::retryOnGreaterThan

Retry the function when the return value is greater than a specific value.

$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnGreaterThan(42);
$callable();

::returnOnGreaterThan

Return from the function when the return value is greater than a specific value.

$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnGreaterThan(42);
$callable();

::retryOnGreaterThanOrEquals

Retry the function when the return value is greater than or equal to a specific value.

$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnGreaterThanOrEquals(42);
$callable();

::returnOnGreaterThanOrEquals

Return from the function when the return value is greater than or equal to a specific value.

$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnGreaterThanOrEquals(42);
$callable();

::retryOnLessThan

Retry the function when the return value is less than a specific value.

$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnLessThan(42);
$callable();

::returnOnLessThan

Return from the function when the return value is less than a specific value.

$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnLessThan(42);
$callable();

::retryOnLessThanOrEquals

Retry the function when the return value is less than or equal to a specific value.

$callable = ConfigurableCallable::factory("myFunction");
$callable->retryOnLessThanOrEquals(42);
$callable();

::returnOnLessThanOrEquals

Return from the function when the return value is less than or equal to a specific value.

$callable = ConfigurableCallable::factory("myFunction");
$callable->returnOnLessThanOrEquals(42);
$callable();