在Laravel中使用API时的处理速率限制



在我的Laravel应用程序中,我广泛使用HubSpot API来执行各种操作。我在文档中看到,你可以在每10秒的时间内发出150个请求。

要监视HubSpot,在进行任何API调用时提供以下头文件:

"X-HubSpot-RateLimit-Daily" => array:1 [▶]
"X-HubSpot-RateLimit-Daily-Remaining" => array:1 [▶]
"X-HubSpot-RateLimit-Interval-Milliseconds" => array:1 [▶]
"X-HubSpot-RateLimit-Max" => array:1 [▶]
"X-HubSpot-RateLimit-Remaining" => array:1 [▶]
"X-HubSpot-RateLimit-Secondly" => array:1 [▶]
"X-HubSpot-RateLimit-Secondly-Remaining" => array:1 [▶]

在我的应用程序中,我正在使用Laravel的Http客户端,它基本上只是Guzzle的包装。

为了遵守速率限制,我真的只需要在每个请求周围包装一个if语句吗?

下面是一个例子:

端点美元= ' https://api.hubapi.com/crm/v3/owners/';

$response = Http::get($endpoint, [
'limit' => 100,
'hapikey' => config('hubspot.api_key'),
]);

在这种情况下,$response将包含报头,但是否有一种方法可以有效地使用它们,因为我肯定只知道一旦我进行了API调用,费率是多少?

我问,因为我必须拉下1000 +交易,然后更新一些记录,但这肯定会超过API限制。作为参考,下面是我写的命令。


<?php
namespace AppConsoleCommands;
use AppEventsDealImportedFromHubspot;
use AppHubspotPipelineHubspot;
use AppModelsDeal;
use AppModelsDealStage;
use IlluminateConsoleCommand;
use IlluminateSupportFacadesHttp;
class ImportHubspotDeals extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'import:hubspot-deals
{--force : Whether we should force the command}
';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Import Deal objects from the HubSpot API in bulk.';
/**
* An array to store imported Deals
*
* @var array
*/
private $importedDeals = [];
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$this->line('Importing Pipelines & Deal Stages from HubSpot API...');
PipelineHubspot::import();
$this->line('Importing Deals from HubSpot API...');
$this->getDealsFromHubspot();
$this->line('Found ' . count($this->importedDeals) . ' Deals to import');
if ($this->option('force')) {
$this->doImport();
} else {
if ($this->confirm('Do you want to import these deals? (yes|no)', false)) {
$this->doImport();
} else {
$this->line('Process aborted');
}
}
}
/**
* Grab Deals from Hubspot by calling the Deals API and looping through the paginated data
*
* @param int    $limit: the number of deals per page
* @param string $next:  the link to the next page of results
*/
private function getDealsFromHubspot(?int $limit = 100, string $next = null)
{
$endpoint = 'https://api.hubapi.com/crm/v3/objects/deals';
$properties = [
'limit' => $limit,
'properties' => implode(',', Deal::HUBSPOT_DEAL_PROPERTIES),
'hapikey' => config('hubspot.api_key'),
'associations' => 'engagements',
];
// If there's another page, append the after parameter.
if ($next) {
$properties['after'] = $next;
}
$response = Http::get($endpoint, $properties);
if ($response->successful()) {
$data = $response->json();
// If there are results, get them.
if (isset($data['results'])) {
foreach ($data['results'] as $hubspotDeal) {
$this->importedDeals[] = $hubspotDeal['properties'];
}
}
// If there's paginate we need to call the function on itself
if (isset($data['paging']['next']['link'])) {
$this->getDealsFromHubspot(null, $data['paging']['next']['after']);
}
}
$response->json();
}
/**
* Pull the Deal data in order to create a Deal model.
*
* @param array $data
*/
private function syncDeal(array $data)
{
$excludedDealStages = DealStage::excludeFromDealImport()->pluck('hubspot_id');
if ($excludedDealStages->contains($data['dealstage'])) {
return false;
}
$deal = Deal::updateOrCreate([
'hubspot_id' => $data['hs_object_id'],
], [
'name' => $data['dealname'],
'deal_stage_id' => $data['dealstage'],
'hubspot_owner_id' => $data['hubspot_owner_id'] ?? null,
]);
event(new DealImportedFromHubspot($deal));
return $deal;
}
/**
* Create and increment a nice progress bar as we import deals.
*/
private function doImport()
{
$bar = $this->output->createProgressBar(count($this->importedDeals));
$bar->start();
foreach ($this->importedDeals as $deal) {
$this->syncDeal($deal);
$bar->advance();
}
$bar->finish();
$this->newLine(2);
$this->line('Successfully imported ' . count($this->importedDeals) . ' Deals from HubSpot.');
}
}

在此基础上构建event(new DealImportedFromHubspot($deal));还会对HubSpot进行API回调,以添加刚刚被拉入的门户的URL。

在这种情况下,我认为我要么需要将交易导入视为自己的工作,要么添加某种速率限制。

仅仅使用sleep(10)来绕过速率限制是不好的做法吗?

听起来像是Queue的工作。

您可以在Queue上定义自己的速率限制器,但正确的解决方案可能是扩展ShouldQueue并在收到请求已被节流的响应时运行$this->fail()

最新更新