I have a working API (php-laravel) that returns the correct data as required. Myself being a java guy I am unable to fully understand what is going wrong. The code was written by a freelancer and I am slowly learning laravel.
The issue is if this particular API is called (even once), the CPU usage on the server hits 100% which shouldnt be the case.
The snippet below is used to check if the promos are applicable to user's cards.
$has_promo_for_users_cards = in_array($promo_summary_id, \User::getPromoSummaryIdsWhereUserHasCards($user_id));
$promo_summary['has_promo_for_users_cards'] = $has_promo_for_users_cards;
// see if the promo is applicable to users cards
if ($has_promo_for_users_cards)
{
$applicable_cards = [];
$filter_cards = $inputs['filter_cards'];
$user_card_ids = $filter_cards == 'my_cards' ? \User::getUsersCardIds($user_id) : explode(',', $inputs['specific_cards']);
foreach ($cards as $card)
{
if (in_array($card['id'], $user_card_ids))
{
array_push($applicable_cards, $card);
}
}
} else
{
// if not applicable then return all the cards
$applicable_cards = $cards;
}
$promo_summary['applicable_cards'] = $applicable_cards;
return $promo_summary;
And returns the whole promo_summary data.
After much experimenting, if I comment out the above snippet, the API response time is much faster and it's also loading the CPU upto 10% only. So I think the problem lies in this snippet. Any suggestions of how this can be optimized? Is there something that is done in a wrong way here?
EDIT 1
Here is the server benchmark results:
ab -n 1000 -c 5 http://111.111.111.111/index.html
This is ApacheBench, Version 2.3 <$Revision: 1554214 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 111.111.111.111 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests
Server Software: Apache/2.4.7
Server Hostname: 111.111.111.111
Server Port: 80
Document Path: /index.html
Document Length: 59598 bytes
Concurrency Level: 5
Time taken for tests: 51.674 seconds
Complete requests: 1000
Failed requests: 113
(Connect: 0, Receive: 0, Length: 113, Exceptions: 0)
Non-2xx responses: 1000
Total transferred: 60176968 bytes
HTML transferred: 59597874 bytes
Requests per second: 19.35 [#/sec] (mean)
Time per request: 258.372 [ms] (mean)
Time per request: 51.674 [ms] (mean, across all concurrent requests)
Transfer rate: 1137.25 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 4 6 1.9 5 56
Processing: 102 252 129.6 175 762
Waiting: 84 231 128.1 154 609
Total: 107 258 129.7 181 767
Percentage of the requests served within a certain time (ms)
50% 181
66% 288
75% 321
80% 336
90% 471
95% 579
98% 616
99% 619
100% 767 (longest request)
EDIT 2 In the code above there is an external call to the "User" model class; A funtion called "getPromoSummaryIdsWhereUserHasCards" specifically. Here there are 2 foreach loops within each other. If I print and check some logs these for loops are getting executed quite a lot of times!
/**
* @param $user_id
* @return array promo_summary_ids_where_user_has_cards
*/
public static function getPromoSummaryIdsWhereUserHasCards($user_id)
{
//logs
ini_set("log_errors", 1);
ini_set("error_log", "/tmp/php-error.log");
//THE BELOW LINE IS TAKING TIME TO EXECUTE
$user = \User::with('cards.promos.promo_summary.establishment')->findOrFail($user_id);
$user_cards = $user->cards;
$promo_summary_ids_where_user_has_cards = [];
foreach ($user_cards as $user_card)
{
error_log( "Foreach user_cards--!");
$promos = $user_card->promos;
foreach ($promos as $promo)
{
error_log( "Foreach promos--!");
$promo_summary = $promo->promo_summary;
array_push($promo_summary_ids_where_user_has_cards, $promo_summary->id);
}
}
return array_unique($promo_summary_ids_where_user_has_cards);
}
EDIT 3 PromoSummary model
<?php
class PromoSummary extends \Eloquent {
protected $guarded = [];
public function promos()
{
return $this->hasMany('Promo', 'promo_summary_id');
}
public function establishment()
{
return $this->belongsTo('Establishment', 'establishment_id');
}
public function searchTags()
{
return $this->hasMany('SearchTag', 'promo_summary_id');
}
/**
* @param $value
* @return mixed
* This is where the Establishment Image url is overriding the image_url in the promo summary.
* If need to change back to normal behaviour change here
*/
public function getImageUrlAttribute($value)
{
return $this->establishment->image_url;
}
}