Scaling third party integrations
class TrafficController extends Controller {
private static $allowed_actions = array('incidents');
public function incidents($request) {
$service = new RestfulService(TRAFFIC_API_URL);
$response = $service->request('/incidents');
return ($response->isError()) ? json_encode($response->getBody()) : '';
}
}
RestfulService - y u no Guzzle?
Empty return value with HTTP 200 = bad
class TrafficController extends Controller {
private static $allowed_actions = array('incidents');
public function incidents($request) {
$service = new RestfulService(TRAFFIC_API_URL);
$response = $service->request('/incidents');
if($response->isError()) {
return $this->httpError(500);
}
return json_encode($response->getBody());
}
}
How do you test the service?
class TrafficController extends Controller {
protected $trafficService;
private static $allowed_actions = array('incidents');
public function __construct() {
parent::__construct();
$this->trafficService = Injector::inst()->create(
'TrafficService',
TRAFFIC_API_URL
);
}
public function incidents($request) {
$incidents = $this->trafficService->getIncidents();
if($incidents === null) {
return $this->httpError(500);
}
return json_encode($incidents);
}
}
class TrafficService {
protected $httpClient;
public function __construct($baseUrl) {
$this->httpClient = new RestfulService($baseUrl);
}
public function getIncidents() {
$response = $this->httpClient->request('/incidents');
if($response->isError()) {
return null;
}
$incidents = $response->getBody();
// ... filter and transform
return $incidents;
}
public function setHttpClient($client) {
$this->httpClient = $client;
}
}
How do you find about about errors?
class TrafficService {
protected $httpClient;
public function __construct($baseUrl) {
$this->httpClient = new RestfulService($baseUrl);
}
public function getIncidents() {
$response = $this->httpClient->request('/incidents');
if($response->isError()) {
SS_Log::log(
sprintf(
'TrafficService::getIncidents() failed with %d: %s',
$response->getStatusCode(),
$response->getBody()
),
SS_Log::WARN
);
return null;
}
$incidents = $response->getBody();
// ... filter and transform
return $incidents;
}
}
Raygun rocks
NFR
class TrafficService {
protected $httpClient;
public function __construct($baseUrl) {
$this->httpClient = new RestfulService($baseUrl);
}
public function getIncidents() {
$response = $this->httpClient->request('/incidents');
if($response->isError()) {
SS_Log::log(
sprintf(
'TrafficService::getIncidents() failed with %d: %s',
$response->getStatusCode(),
$response->getBody()
),
SS_Log::WARN
);
return null;
}
$incidents = $response->getBody();
// ... filter and transform
return $incidents;
}
}
RestfulService caches for an hour by default
Curl settings: 5 seconds connection timeout
Curl settings: No request timeout (just max_execution_time)
Only caches on HTTP success
class GenerateTrafficIncidentsJob extends AbstractQueuedJob implements QueuedJob {
public function __construct(TrafficService $trafficService) {
$this->trafficService = $trafficService;
}
public function process() {
$service = $this->trafficService;
$incidents = $service->getIncidents();
if($incidents === null) {
$this->addMessage('Incidents job failed', 'FAIL');
return;
}
file_put_contents(ASSETS_PATH . '/incidents.json', json_encode($incidents));
$this->completeJob();
}
protected function completeJob() {
$job = new GenerateTrafficIncidentsJob();
singleton('QueuedJobService')->queueJob($job, date('Y-m-d H:i:s', time() + 30));
$this->isComplete = true;
}
}
What if the queue stalls?
class TrafficEnvironmentCheck implements EnvironmentCheck {
protected $maxAgeSecs = 600;
public function check() {
$modTime = filemtime(ASSETS_PATH . '/incidents.json');
$isRecent = $modTime > (time() - $this->maxAgeSecs);
if($isRecent) {
return array(EnvironmentCheck::OK);
} else {
return array(EnvironmentCheck::ERROR, sprintf(
"incidents.json is older than %d secs", $this->maxAgeSecs
));
}
}
}
Operation
Thanks
Scaling third party integrations
By chillu
Scaling third party integrations
- 1,134