Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Distributed Concurrency in PHP using Nginx, PHP5-FPM and Memcache
- An issue I've run into in the past is "how do we perform 5 calls to a 3rd party API, as quickly as possible?" The obvious answer is, make them all at once and wait until they've all come back!
- While PHP does support forking on Unix OSes (http://www.tuxradar.com/practicalphp/16/1/3), the method I am going to explain allows for the requests to be load balanced, and the functionality also makes providing an API to our tools trivial!
- The client part of our code will run the following:
- */
- if(class_exists('\Memcache')) {
- $cache = \Utilities\Utilities::getCache();
- }
- foreach (array('eggs','ham','span','jam') as $term) {
- set_time_limit (60);
- /**
- * Here we are making GET requests for the API URLs, they will return a cacheId,
- * which is like a cloak room ticket, that tells us where the results are when
- * we need to come back and collect them later.
- */
- if(isset($cache) && $cache != FALSE) {
- $cacheIds[$number] = file_get_contents("http://example.com/webservice/searchterm/{$term}");
- }
- $number++;
- }
- if(isset($cacheIds)) {
- $time = 0;
- $responses = array();
- $failcount = 0;
- /**
- * Loop until we have either processed all $cacheIds, been going 5 seconds, or had 10 cache failures.
- */
- while(count($cacheIds) != count($responses) && $time < 5 && $failcount < 10) {
- if($cache != FALSE) {
- /**
- * loop through all $cacheIds, to check if any of them have been populated in the cache.
- */
- foreach($cacheIds as $id => $cacheId) {
- if($responseData = $cache->get($cacheId)) {
- $responses[$id] = $responseData;
- unset($responseData);
- $cache->delete($cacheId);
- }
- }
- }
- else {
- /**
- * If the cache has failed to be set, we try again! It may only have been a temporary issue.
- */
- $cache = \Utilities\Utilities::getCache();
- $failcount++;
- }
- /**
- * The time needs incrementing, and then we sleep, to avoid wasting
- * effort check for a network query too often!
- */
- $time = $time+0.2;
- sleep(0.2);
- }
- /**
- * Check if we had any failures, and report them, otherwise it will be easy
- * to miss that there is an issue.
- */
- if($failcount > 0) {
- trigger_error("Failed $failcount times",E_USER_WARNING);
- }
- /**
- * Check if we ran out of time, if it's happening a lot, it would need investigation!
- */
- if($time == 5) {
- echo "Requests timed out";
- }
- }
- if(!empty($responses) || !class_exists('\Memcache')) {
- foreach ($responses as $response) {
- /**
- * for the first pass, we need to initially set $returnResponse
- * (and not try to do any merging!)
- */
- if(!isset($returnResponse)) {
- $returnResponse = $response;
- }
- else {
- /**
- * as long as the $response is an array, we now merge it with the former
- * responses, to give our merged response.
- */
- if(is_array($response)) {
- $returnResponse = array_merge($returnResponse, $response);
- }
- }
- }
- return $returnResponse;
- }
- /*
- Now, the server side does the following:
- */
- /**
- * The $id will be the cloak room ticket. We simply echo it,
- * and then close the connection (using "fastcgi_finish_request()")
- */
- $id = uniqid();
- echo $id;
- fastcgi_finish_request();
- /**
- * Now that we've closed the connection, we will connect to the cache,
- * inform that model that it is handling a 'webservice' request,
- * and then store the results in the cache, and then we're all done!
- * the results are waiting in the cloakroom, to be picked up shortly :-)
- */
- $cache = \Utilities\Utilities::getCache();
- $this->Search->setWebservice();
- $results = $this->Search->search($this->userParams);
- if($cache != FALSE) {
- $cache->set($id, $results, 60);
- }
- else {
- /**
- * Of course, if it has all gone wrong, we need to know! So we trigger a warning.
- */
- trigger_error("SearchController::webserviceAction error: failed to connect to cache", E_USER_ERROR);
- }
Advertisement
Add Comment
Please, Sign In to add comment