26Mar/092
Rate Limiting SOAP client in PHP
I've recently had the requirement to rate limit SOAP calls to a remote API, so having done the work I though I'd document it here.
I've left in one method in the code below which is specific to my use - SearchAccounts(). The reason for this is that I though I'd show how I go about using it, in that I don't leave calls up to the magical methods that the SoapClient itself provides, but rather re-define the functions in my own class so that I can generate API docs locally. It is of course up to you if you want to use this method.
class ApmSoapClient extends SoapClient { /** * @var int Number of microseconds to wait before consecutive calls */ private $rateLimit = 100; /** * @var float Stores the time of last call, used for ratelimiting */ private $lastcall; public function __construct($wsdl, $username, $password) { parent::__construct($wsdl, array( 'login' => $username, 'password' => $password, 'classmap' => array( 'Mailbox' => 'Mailbox', 'Account' => 'Account', 'MailboxAlias' => 'MailboxAlias', 'Domain' => 'Domain', ) )); } /** * Returns $rateLimit. * @see ApmSoapClient::$rateLimit */ public function getRateLimit() { return $this->rateLimit; } /** * Sets $rateLimit. * @param object $rateLimit * @see ApmSoapClient::$rateLimit */ public function setRateLimit($rateLimit) { $this->rateLimit = $rateLimit; } public function __call($func, $args) { return $this->__soapCall($func, $args); } public function __soapCall($func, $args) { if ($this->lastcall && $this->rateLimit) { if (($this->lastcall + ($this->rateLimit / 1000)) > microtime(true)) { $msSleep = (($this->lastcall + ($this->rateLimit / 1000)) - microtime(true)) * 1000 * 1000; usleep((int)$msSleep); } } $this->lastcall = microtime(true); return parent::__soapCall($func, $args); } /** * * @return array * @param String $ref Your account reference * @param String $statis 1 = On, 0 = Off * @param Integer $overquota 1 = Users over quota, 0 = Any user * @param String $after_date Only users created after this date * @param String $before_date Only users created before this date * @param String $email A valid email address */ public function SearchAccounts($ref, $statis, $overquota, $after_date, $before_date, $email) { $args = func_get_args(); return $this->__call('SearchAccounts', $args); } }
March 26th, 2009 - 17:42
What about concurrent users? This rate limiting works only if one user is involved in making SOAP calls.
March 26th, 2009 - 18:38
indeed it does – i programmed it for a batch job run from the CLI. You could move the rate limiting into shared memory, but I imagine if you’re doing lots of SOAP requests for a single web request, you need to look at the issue from a different angle.