|
16961
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\Middleware;
use Exception;
use Illuminate\Contracts\Queue\Job;
use Illuminate\Support\Facades\Log;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Jobs\Middleware\HandleHubspotRateLimit;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
#[CoversClass(HandleHubspotRateLimit::class)]
class HandleHubspotRateLimitTest extends TestCase
{
private const int MAX_RETRY_DELAY = 600;
private const int MIN_RETRY_DELAY = 1;
private const int JITTER_SECONDS = 5;
private HandleHubspotRateLimit $middleware;
protected function setUp(): void
{
parent::setUp();
$this->middleware = new HandleHubspotRateLimit();
}
public function testPassesThroughWhenNoExceptionThrown(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$called = false;
$next = function (object $passed) use ($job, &$called): void {
$this->assertSame($job, $passed);
$called = true;
};
$this->middleware->handle($job, $next);
$this->assertTrue($called);
}
public function testPropagatesNonRateLimitExceptions(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$next = static function (): void {
throw new Exception('Database is down');
};
$this->expectException(Exception::class);
$this->expectExceptionMessage('Database is down');
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{retryAfter: int, expectedMin: int, expectedMax: int}>
*/
public static function delayClampingProvider(): array
{
return [
'short retry uses retry_after as floor' => [
'retryAfter' => 1,
'expectedMin' => self::MIN_RETRY_DELAY,
'expectedMax' => self::MIN_RETRY_DELAY + self::JITTER_SECONDS,
],
'medium retry passes through' => [
'retryAfter' => 30,
'expectedMin' => 30,
'expectedMax' => 30 + self::JITTER_SECONDS,
],
'large retry clamped to max' => [
'retryAfter' => 86400,
'expectedMin' => self::MAX_RETRY_DELAY,
'expectedMax' => self::MAX_RETRY_DELAY + self::JITTER_SECONDS,
],
];
}
#[DataProvider('delayClampingProvider')]
public function testReleasesJobWithClampedDelay(int $retryAfter, int $expectedMin, int $expectedMax): void
{
Log::shouldReceive('info')->zeroOrMoreTimes();
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn(1);
$job->expects($this->once())
->method('release')
->with($this->callback(static function (int $delay) use ($expectedMin, $expectedMax): bool {
return $delay >= $expectedMin && $delay <= $expectedMax;
}));
$next = static function () use ($retryAfter): void {
throw new RateLimitException('rate limited', $retryAfter);
};
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{attempts: int, shouldLog: bool}>
*/
public static function logSamplingProvider(): array
{
return [
'first attempt logs' => ['attempts' => 1, 'shouldLog' => true],
'second attempt logs' => ['attempts' => 2, 'shouldLog' => true],
'third attempt logs' => ['attempts' => 3, 'shouldLog' => true],
'fourth attempt skipped' => ['attempts' => 4, 'shouldLog' => false],
'ninth attempt skipped' => ['attempts' => 9, 'shouldLog' => false],
'tenth attempt logs (multiple of 10)' => ['attempts' => 10, 'shouldLog' => true],
'eleventh attempt skipped' => ['attempts' => 11, 'shouldLog' => false],
'twentieth attempt logs' => ['attempts' => 20, 'shouldLog' => true],
];
}
#[DataProvider('logSamplingProvider')]
public function testLogSampling(int $attempts, bool $shouldLog): void
{
if ($shouldLog) {
Log::shouldReceive('info')
->once()
->with(
'[HandleHubspotRateLimit] Rate limit caught, releasing job with delay',
$this->callback(static function (array $context) use ($attempts): bool {
return $context['attempts'] === $attempts
&& $context['retry_after'] === 1
&& isset($context['delay']);
})
);
} else {
Log::shouldReceive('info')->never();
}
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn($attempts);
$job->expects($this->once())->method('release');
$next = static function (): void {
throw new RateLimitException('rate limited', 1);
};
$this->middleware->handle($job, $next);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
PhpStorm
|
faVsco.js – HandleHubspotRateLimitTest.php
|
NULL
|
16961
|
|
16962
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\Middleware;
use Exception;
use Illuminate\Contracts\Queue\Job;
use Illuminate\Support\Facades\Log;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Jobs\Middleware\HandleHubspotRateLimit;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
#[CoversClass(HandleHubspotRateLimit::class)]
class HandleHubspotRateLimitTest extends TestCase
{
private const int MAX_RETRY_DELAY = 600;
private const int MIN_RETRY_DELAY = 1;
private const int JITTER_SECONDS = 5;
private HandleHubspotRateLimit $middleware;
protected function setUp(): void
{
parent::setUp();
$this->middleware = new HandleHubspotRateLimit();
}
public function testPassesThroughWhenNoExceptionThrown(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$called = false;
$next = function (object $passed) use ($job, &$called): void {
$this->assertSame($job, $passed);
$called = true;
};
$this->middleware->handle($job, $next);
$this->assertTrue($called);
}
public function testPropagatesNonRateLimitExceptions(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$next = static function (): void {
throw new Exception('Database is down');
};
$this->expectException(Exception::class);
$this->expectExceptionMessage('Database is down');
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{retryAfter: int, expectedMin: int, expectedMax: int}>
*/
public static function delayClampingProvider(): array
{
return [
'short retry uses retry_after as floor' => [
'retryAfter' => 1,
'expectedMin' => self::MIN_RETRY_DELAY,
'expectedMax' => self::MIN_RETRY_DELAY + self::JITTER_SECONDS,
],
'medium retry passes through' => [
'retryAfter' => 30,
'expectedMin' => 30,
'expectedMax' => 30 + self::JITTER_SECONDS,
],
'large retry clamped to max' => [
'retryAfter' => 86400,
'expectedMin' => self::MAX_RETRY_DELAY,
'expectedMax' => self::MAX_RETRY_DELAY + self::JITTER_SECONDS,
],
];
}
#[DataProvider('delayClampingProvider')]
public function testReleasesJobWithClampedDelay(int $retryAfter, int $expectedMin, int $expectedMax): void
{
Log::shouldReceive('info')->zeroOrMoreTimes();
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn(1);
$job->expects($this->once())
->method('release')
->with($this->callback(static function (int $delay) use ($expectedMin, $expectedMax): bool {
return $delay >= $expectedMin && $delay <= $expectedMax;
}));
$next = static function () use ($retryAfter): void {
throw new RateLimitException('rate limited', $retryAfter);
};
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{attempts: int, shouldLog: bool}>
*/
public static function logSamplingProvider(): array
{
return [
'first attempt logs' => ['attempts' => 1, 'shouldLog' => true],
'second attempt logs' => ['attempts' => 2, 'shouldLog' => true],
'third attempt logs' => ['attempts' => 3, 'shouldLog' => true],
'fourth attempt skipped' => ['attempts' => 4, 'shouldLog' => false],
'ninth attempt skipped' => ['attempts' => 9, 'shouldLog' => false],
'tenth attempt logs (multiple of 10)' => ['attempts' => 10, 'shouldLog' => true],
'eleventh attempt skipped' => ['attempts' => 11, 'shouldLog' => false],
'twentieth attempt logs' => ['attempts' => 20, 'shouldLog' => true],
];
}
#[DataProvider('logSamplingProvider')]
public function testLogSampling(int $attempts, bool $shouldLog): void
{
if ($shouldLog) {
Log::shouldReceive('info')
->once()
->with(
'[HandleHubspotRateLimit] Rate limit caught, releasing job with delay',
$this->callback(static function (array $context) use ($attempts): bool {
return $context['attempts'] === $attempts
&& $context['retry_after'] === 1
&& isset($context['delay']);
})
);
} else {
Log::shouldReceive('info')->never();
}
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn($attempts);
$job->expects($this->once())->method('release');
$next = static function (): void {
throw new RateLimitException('rate limited', 1);
};
$this->middleware->handle($job, $next);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
PhpStorm
|
faVsco.js – HandleHubspotRateLimitTest.php
|
NULL
|
16962
|
|
16963
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\Middleware;
use Exception;
use Illuminate\Contracts\Queue\Job;
use Illuminate\Support\Facades\Log;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Jobs\Middleware\HandleHubspotRateLimit;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
#[CoversClass(HandleHubspotRateLimit::class)]
class HandleHubspotRateLimitTest extends TestCase
{
private const int MAX_RETRY_DELAY = 600;
private const int MIN_RETRY_DELAY = 1;
private const int JITTER_SECONDS = 5;
private HandleHubspotRateLimit $middleware;
protected function setUp(): void
{
parent::setUp();
$this->middleware = new HandleHubspotRateLimit();
}
public function testPassesThroughWhenNoExceptionThrown(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$called = false;
$next = function (object $passed) use ($job, &$called): void {
$this->assertSame($job, $passed);
$called = true;
};
$this->middleware->handle($job, $next);
$this->assertTrue($called);
}
public function testPropagatesNonRateLimitExceptions(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$next = static function (): void {
throw new Exception('Database is down');
};
$this->expectException(Exception::class);
$this->expectExceptionMessage('Database is down');
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{retryAfter: int, expectedMin: int, expectedMax: int}>
*/
public static function delayClampingProvider(): array
{
return [
'short retry uses retry_after as floor' => [
'retryAfter' => 1,
'expectedMin' => self::MIN_RETRY_DELAY,
'expectedMax' => self::MIN_RETRY_DELAY + self::JITTER_SECONDS,
],
'medium retry passes through' => [
'retryAfter' => 30,
'expectedMin' => 30,
'expectedMax' => 30 + self::JITTER_SECONDS,
],
'large retry clamped to max' => [
'retryAfter' => 86400,
'expectedMin' => self::MAX_RETRY_DELAY,
'expectedMax' => self::MAX_RETRY_DELAY + self::JITTER_SECONDS,
],
];
}
#[DataProvider('delayClampingProvider')]
public function testReleasesJobWithClampedDelay(int $retryAfter, int $expectedMin, int $expectedMax): void
{
Log::shouldReceive('info')->zeroOrMoreTimes();
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn(1);
$job->expects($this->once())
->method('release')
->with($this->callback(static function (int $delay) use ($expectedMin, $expectedMax): bool {
return $delay >= $expectedMin && $delay <= $expectedMax;
}));
$next = static function () use ($retryAfter): void {
throw new RateLimitException('rate limited', $retryAfter);
};
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{attempts: int, shouldLog: bool}>
*/
public static function logSamplingProvider(): array
{
return [
'first attempt logs' => ['attempts' => 1, 'shouldLog' => true],
'second attempt logs' => ['attempts' => 2, 'shouldLog' => true],
'third attempt logs' => ['attempts' => 3, 'shouldLog' => true],
'fourth attempt skipped' => ['attempts' => 4, 'shouldLog' => false],
'ninth attempt skipped' => ['attempts' => 9, 'shouldLog' => false],
'tenth attempt logs (multiple of 10)' => ['attempts' => 10, 'shouldLog' => true],
'eleventh attempt skipped' => ['attempts' => 11, 'shouldLog' => false],
'twentieth attempt logs' => ['attempts' => 20, 'shouldLog' => true],
];
}
#[DataProvider('logSamplingProvider')]
public function testLogSampling(int $attempts, bool $shouldLog): void
{
if ($shouldLog) {
Log::shouldReceive('info')
->once()
->with(
'[HandleHubspotRateLimit] Rate limit caught, releasing job with delay',
$this->callback(static function (array $context) use ($attempts): bool {
return $context['attempts'] === $attempts
&& $context['retry_after'] === 1
&& isset($context['delay']);
})
);
} else {
Log::shouldReceive('info')->never();
}
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn($attempts);
$job->expects($this->once())->method('release');
$next = static function (): void {
throw new RateLimitException('rate limited', 1);
};
$this->middleware->handle($job, $next);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
PhpStorm
|
faVsco.js – HandleHubspotRateLimitTest.php
|
NULL
|
16963
|
|
16964
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\Middleware;
use Exception;
use Illuminate\Contracts\Queue\Job;
use Illuminate\Support\Facades\Log;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Jobs\Middleware\HandleHubspotRateLimit;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
#[CoversClass(HandleHubspotRateLimit::class)]
class HandleHubspotRateLimitTest extends TestCase
{
private const int MAX_RETRY_DELAY = 600;
private const int MIN_RETRY_DELAY = 1;
private const int JITTER_SECONDS = 5;
private HandleHubspotRateLimit $middleware;
protected function setUp(): void
{
parent::setUp();
$this->middleware = new HandleHubspotRateLimit();
}
public function testPassesThroughWhenNoExceptionThrown(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$called = false;
$next = function (object $passed) use ($job, &$called): void {
$this->assertSame($job, $passed);
$called = true;
};
$this->middleware->handle($job, $next);
$this->assertTrue($called);
}
public function testPropagatesNonRateLimitExceptions(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$next = static function (): void {
throw new Exception('Database is down');
};
$this->expectException(Exception::class);
$this->expectExceptionMessage('Database is down');
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{retryAfter: int, expectedMin: int, expectedMax: int}>
*/
public static function delayClampingProvider(): array
{
return [
'short retry uses retry_after as floor' => [
'retryAfter' => 1,
'expectedMin' => self::MIN_RETRY_DELAY,
'expectedMax' => self::MIN_RETRY_DELAY + self::JITTER_SECONDS,
],
'medium retry passes through' => [
'retryAfter' => 30,
'expectedMin' => 30,
'expectedMax' => 30 + self::JITTER_SECONDS,
],
'large retry clamped to max' => [
'retryAfter' => 86400,
'expectedMin' => self::MAX_RETRY_DELAY,
'expectedMax' => self::MAX_RETRY_DELAY + self::JITTER_SECONDS,
],
];
}
#[DataProvider('delayClampingProvider')]
public function testReleasesJobWithClampedDelay(int $retryAfter, int $expectedMin, int $expectedMax): void
{
Log::shouldReceive('info')->zeroOrMoreTimes();
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn(1);
$job->expects($this->once())
->method('release')
->with($this->callback(static function (int $delay) use ($expectedMin, $expectedMax): bool {
return $delay >= $expectedMin && $delay <= $expectedMax;
}));
$next = static function () use ($retryAfter): void {
throw new RateLimitException('rate limited', $retryAfter);
};
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{attempts: int, shouldLog: bool}>
*/
public static function logSamplingProvider(): array
{
return [
'first attempt logs' => ['attempts' => 1, 'shouldLog' => true],
'second attempt logs' => ['attempts' => 2, 'shouldLog' => true],
'third attempt logs' => ['attempts' => 3, 'shouldLog' => true],
'fourth attempt skipped' => ['attempts' => 4, 'shouldLog' => false],
'ninth attempt skipped' => ['attempts' => 9, 'shouldLog' => false],
'tenth attempt logs (multiple of 10)' => ['attempts' => 10, 'shouldLog' => true],
'eleventh attempt skipped' => ['attempts' => 11, 'shouldLog' => false],
'twentieth attempt logs' => ['attempts' => 20, 'shouldLog' => true],
];
}
#[DataProvider('logSamplingProvider')]
public function testLogSampling(int $attempts, bool $shouldLog): void
{
if ($shouldLog) {
Log::shouldReceive('info')
->once()
->with(
'[HandleHubspotRateLimit] Rate limit caught, releasing job with delay',
$this->callback(static function (array $context) use ($attempts): bool {
return $context['attempts'] === $attempts
&& $context['retry_after'] === 1
&& isset($context['delay']);
})
);
} else {
Log::shouldReceive('info')->never();
}
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn($attempts);
$job->expects($this->once())->method('release');
$next = static function (): void {
throw new RateLimitException('rate limited', 1);
};
$this->middleware->handle($job, $next);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
PhpStorm
|
faVsco.js – HandleHubspotRateLimitTest.php
|
NULL
|
16964
|
|
16965
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\Middleware;
use Exception;
use Illuminate\Contracts\Queue\Job;
use Illuminate\Support\Facades\Log;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Jobs\Middleware\HandleHubspotRateLimit;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
#[CoversClass(HandleHubspotRateLimit::class)]
class HandleHubspotRateLimitTest extends TestCase
{
private const int MAX_RETRY_DELAY = 600;
private const int MIN_RETRY_DELAY = 1;
private const int JITTER_SECONDS = 5;
private HandleHubspotRateLimit $middleware;
protected function setUp(): void
{
parent::setUp();
$this->middleware = new HandleHubspotRateLimit();
}
public function testPassesThroughWhenNoExceptionThrown(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$called = false;
$next = function (object $passed) use ($job, &$called): void {
$this->assertSame($job, $passed);
$called = true;
};
$this->middleware->handle($job, $next);
$this->assertTrue($called);
}
public function testPropagatesNonRateLimitExceptions(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$next = static function (): void {
throw new Exception('Database is down');
};
$this->expectException(Exception::class);
$this->expectExceptionMessage('Database is down');
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{retryAfter: int, expectedMin: int, expectedMax: int}>
*/
public static function delayClampingProvider(): array
{
return [
'short retry uses retry_after as floor' => [
'retryAfter' => 1,
'expectedMin' => self::MIN_RETRY_DELAY,
'expectedMax' => self::MIN_RETRY_DELAY + self::JITTER_SECONDS,
],
'medium retry passes through' => [
'retryAfter' => 30,
'expectedMin' => 30,
'expectedMax' => 30 + self::JITTER_SECONDS,
],
'large retry clamped to max' => [
'retryAfter' => 86400,
'expectedMin' => self::MAX_RETRY_DELAY,
'expectedMax' => self::MAX_RETRY_DELAY + self::JITTER_SECONDS,
],
];
}
#[DataProvider('delayClampingProvider')]
public function testReleasesJobWithClampedDelay(int $retryAfter, int $expectedMin, int $expectedMax): void
{
Log::shouldReceive('info')->zeroOrMoreTimes();
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn(1);
$job->expects($this->once())
->method('release')
->with($this->callback(static function (int $delay) use ($expectedMin, $expectedMax): bool {
return $delay >= $expectedMin && $delay <= $expectedMax;
}));
$next = static function () use ($retryAfter): void {
throw new RateLimitException('rate limited', $retryAfter);
};
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{attempts: int, shouldLog: bool}>
*/
public static function logSamplingProvider(): array
{
return [
'first attempt logs' => ['attempts' => 1, 'shouldLog' => true],
'second attempt logs' => ['attempts' => 2, 'shouldLog' => true],
'third attempt logs' => ['attempts' => 3, 'shouldLog' => true],
'fourth attempt skipped' => ['attempts' => 4, 'shouldLog' => false],
'ninth attempt skipped' => ['attempts' => 9, 'shouldLog' => false],
'tenth attempt logs (multiple of 10)' => ['attempts' => 10, 'shouldLog' => true],
'eleventh attempt skipped' => ['attempts' => 11, 'shouldLog' => false],
'twentieth attempt logs' => ['attempts' => 20, 'shouldLog' => true],
];
}
#[DataProvider('logSamplingProvider')]
public function testLogSampling(int $attempts, bool $shouldLog): void
{
if ($shouldLog) {
Log::shouldReceive('info')
->once()
->with(
'[HandleHubspotRateLimit] Rate limit caught, releasing job with delay',
$this->callback(static function (array $context) use ($attempts): bool {
return $context['attempts'] === $attempts
&& $context['retry_after'] === 1
&& isset($context['delay']);
})
);
} else {
Log::shouldReceive('info')->never();
}
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn($attempts);
$job->expects($this->once())->method('release');
$next = static function (): void {
throw new RateLimitException('rate limited', 1);
};
$this->middleware->handle($job, $next);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
PhpStorm
|
faVsco.js – HandleHubspotRateLimitTest.php
|
NULL
|
16965
|
|
16966
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\Middleware;
use Exception;
use Illuminate\Contracts\Queue\Job;
use Illuminate\Support\Facades\Log;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Jobs\Middleware\HandleHubspotRateLimit;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
#[CoversClass(HandleHubspotRateLimit::class)]
class HandleHubspotRateLimitTest extends TestCase
{
private const int MAX_RETRY_DELAY = 600;
private const int MIN_RETRY_DELAY = 1;
private const int JITTER_SECONDS = 5;
private HandleHubspotRateLimit $middleware;
protected function setUp(): void
{
parent::setUp();
$this->middleware = new HandleHubspotRateLimit();
}
public function testPassesThroughWhenNoExceptionThrown(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$called = false;
$next = function (object $passed) use ($job, &$called): void {
$this->assertSame($job, $passed);
$called = true;
};
$this->middleware->handle($job, $next);
$this->assertTrue($called);
}
public function testPropagatesNonRateLimitExceptions(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$next = static function (): void {
throw new Exception('Database is down');
};
$this->expectException(Exception::class);
$this->expectExceptionMessage('Database is down');
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{retryAfter: int, expectedMin: int, expectedMax: int}>
*/
public static function delayClampingProvider(): array
{
return [
'short retry uses retry_after as floor' => [
'retryAfter' => 1,
'expectedMin' => self::MIN_RETRY_DELAY,
'expectedMax' => self::MIN_RETRY_DELAY + self::JITTER_SECONDS,
],
'medium retry passes through' => [
'retryAfter' => 30,
'expectedMin' => 30,
'expectedMax' => 30 + self::JITTER_SECONDS,
],
'large retry clamped to max' => [
'retryAfter' => 86400,
'expectedMin' => self::MAX_RETRY_DELAY,
'expectedMax' => self::MAX_RETRY_DELAY + self::JITTER_SECONDS,
],
];
}
#[DataProvider('delayClampingProvider')]
public function testReleasesJobWithClampedDelay(int $retryAfter, int $expectedMin, int $expectedMax): void
{
Log::shouldReceive('info')->zeroOrMoreTimes();
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn(1);
$job->expects($this->once())
->method('release')
->with($this->callback(static function (int $delay) use ($expectedMin, $expectedMax): bool {
return $delay >= $expectedMin && $delay <= $expectedMax;
}));
$next = static function () use ($retryAfter): void {
throw new RateLimitException('rate limited', $retryAfter);
};
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{attempts: int, shouldLog: bool}>
*/
public static function logSamplingProvider(): array
{
return [
'first attempt logs' => ['attempts' => 1, 'shouldLog' => true],
'second attempt logs' => ['attempts' => 2, 'shouldLog' => true],
'third attempt logs' => ['attempts' => 3, 'shouldLog' => true],
'fourth attempt skipped' => ['attempts' => 4, 'shouldLog' => false],
'ninth attempt skipped' => ['attempts' => 9, 'shouldLog' => false],
'tenth attempt logs (multiple of 10)' => ['attempts' => 10, 'shouldLog' => true],
'eleventh attempt skipped' => ['attempts' => 11, 'shouldLog' => false],
'twentieth attempt logs' => ['attempts' => 20, 'shouldLog' => true],
];
}
#[DataProvider('logSamplingProvider')]
public function testLogSampling(int $attempts, bool $shouldLog): void
{
if ($shouldLog) {
Log::shouldReceive('info')
->once()
->with(
'[HandleHubspotRateLimit] Rate limit caught, releasing job with delay',
$this->callback(static function (array $context) use ($attempts): bool {
return $context['attempts'] === $attempts
&& $context['retry_after'] === 1
&& isset($context['delay']);
})
);
} else {
Log::shouldReceive('info')->never();
}
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn($attempts);
$job->expects($this->once())->method('release');
$next = static function (): void {
throw new RateLimitException('rate limited', 1);
};
$this->middleware->handle($job, $next);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
PhpStorm
|
faVsco.js – HandleHubspotRateLimitTest.php
|
NULL
|
16966
|
|
16967
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\Middleware;
use Exception;
use Illuminate\Contracts\Queue\Job;
use Illuminate\Support\Facades\Log;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Jobs\Middleware\HandleHubspotRateLimit;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
#[CoversClass(HandleHubspotRateLimit::class)]
class HandleHubspotRateLimitTest extends TestCase
{
private const int MAX_RETRY_DELAY = 600;
private const int MIN_RETRY_DELAY = 1;
private const int JITTER_SECONDS = 5;
private HandleHubspotRateLimit $middleware;
protected function setUp(): void
{
parent::setUp();
$this->middleware = new HandleHubspotRateLimit();
}
public function testPassesThroughWhenNoExceptionThrown(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$called = false;
$next = function (object $passed) use ($job, &$called): void {
$this->assertSame($job, $passed);
$called = true;
};
$this->middleware->handle($job, $next);
$this->assertTrue($called);
}
public function testPropagatesNonRateLimitExceptions(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$next = static function (): void {
throw new Exception('Database is down');
};
$this->expectException(Exception::class);
$this->expectExceptionMessage('Database is down');
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{retryAfter: int, expectedMin: int, expectedMax: int}>
*/
public static function delayClampingProvider(): array
{
return [
'short retry uses retry_after as floor' => [
'retryAfter' => 1,
'expectedMin' => self::MIN_RETRY_DELAY,
'expectedMax' => self::MIN_RETRY_DELAY + self::JITTER_SECONDS,
],
'medium retry passes through' => [
'retryAfter' => 30,
'expectedMin' => 30,
'expectedMax' => 30 + self::JITTER_SECONDS,
],
'large retry clamped to max' => [
'retryAfter' => 86400,
'expectedMin' => self::MAX_RETRY_DELAY,
'expectedMax' => self::MAX_RETRY_DELAY + self::JITTER_SECONDS,
],
];
}
#[DataProvider('delayClampingProvider')]
public function testReleasesJobWithClampedDelay(int $retryAfter, int $expectedMin, int $expectedMax): void
{
Log::shouldReceive('info')->zeroOrMoreTimes();
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn(1);
$job->expects($this->once())
->method('release')
->with($this->callback(static function (int $delay) use ($expectedMin, $expectedMax): bool {
return $delay >= $expectedMin && $delay <= $expectedMax;
}));
$next = static function () use ($retryAfter): void {
throw new RateLimitException('rate limited', $retryAfter);
};
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{attempts: int, shouldLog: bool}>
*/
public static function logSamplingProvider(): array
{
return [
'first attempt logs' => ['attempts' => 1, 'shouldLog' => true],
'second attempt logs' => ['attempts' => 2, 'shouldLog' => true],
'third attempt logs' => ['attempts' => 3, 'shouldLog' => true],
'fourth attempt skipped' => ['attempts' => 4, 'shouldLog' => false],
'ninth attempt skipped' => ['attempts' => 9, 'shouldLog' => false],
'tenth attempt logs (multiple of 10)' => ['attempts' => 10, 'shouldLog' => true],
'eleventh attempt skipped' => ['attempts' => 11, 'shouldLog' => false],
'twentieth attempt logs' => ['attempts' => 20, 'shouldLog' => true],
];
}
#[DataProvider('logSamplingProvider')]
public function testLogSampling(int $attempts, bool $shouldLog): void
{
if ($shouldLog) {
Log::shouldReceive('info')
->once()
->with(
'[HandleHubspotRateLimit] Rate limit caught, releasing job with delay',
$this->callback(static function (array $context) use ($attempts): bool {
return $context['attempts'] === $attempts
&& $context['retry_after'] === 1
&& isset($context['delay']);
})
);
} else {
Log::shouldReceive('info')->never();
}
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn($attempts);
$job->expects($this->once())->method('release');
$next = static function (): void {
throw new RateLimitException('rate limited', 1);
};
$this->middleware->handle($job, $next);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
PhpStorm
|
faVsco.js – HandleHubspotRateLimitTest.php
|
NULL
|
16967
|
|
16968
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\Middleware;
use Exception;
use Illuminate\Contracts\Queue\Job;
use Illuminate\Support\Facades\Log;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Jobs\Middleware\HandleHubspotRateLimit;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
#[CoversClass(HandleHubspotRateLimit::class)]
class HandleHubspotRateLimitTest extends TestCase
{
private const int MAX_RETRY_DELAY = 600;
private const int MIN_RETRY_DELAY = 1;
private const int JITTER_SECONDS = 5;
private HandleHubspotRateLimit $middleware;
protected function setUp(): void
{
parent::setUp();
$this->middleware = new HandleHubspotRateLimit();
}
public function testPassesThroughWhenNoExceptionThrown(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$called = false;
$next = function (object $passed) use ($job, &$called): void {
$this->assertSame($job, $passed);
$called = true;
};
$this->middleware->handle($job, $next);
$this->assertTrue($called);
}
public function testPropagatesNonRateLimitExceptions(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$next = static function (): void {
throw new Exception('Database is down');
};
$this->expectException(Exception::class);
$this->expectExceptionMessage('Database is down');
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{retryAfter: int, expectedMin: int, expectedMax: int}>
*/
public static function delayClampingProvider(): array
{
return [
'short retry uses retry_after as floor' => [
'retryAfter' => 1,
'expectedMin' => self::MIN_RETRY_DELAY,
'expectedMax' => self::MIN_RETRY_DELAY + self::JITTER_SECONDS,
],
'medium retry passes through' => [
'retryAfter' => 30,
'expectedMin' => 30,
'expectedMax' => 30 + self::JITTER_SECONDS,
],
'large retry clamped to max' => [
'retryAfter' => 86400,
'expectedMin' => self::MAX_RETRY_DELAY,
'expectedMax' => self::MAX_RETRY_DELAY + self::JITTER_SECONDS,
],
];
}
#[DataProvider('delayClampingProvider')]
public function testReleasesJobWithClampedDelay(int $retryAfter, int $expectedMin, int $expectedMax): void
{
Log::shouldReceive('info')->zeroOrMoreTimes();
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn(1);
$job->expects($this->once())
->method('release')
->with($this->callback(static function (int $delay) use ($expectedMin, $expectedMax): bool {
return $delay >= $expectedMin && $delay <= $expectedMax;
}));
$next = static function () use ($retryAfter): void {
throw new RateLimitException('rate limited', $retryAfter);
};
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{attempts: int, shouldLog: bool}>
*/
public static function logSamplingProvider(): array
{
return [
'first attempt logs' => ['attempts' => 1, 'shouldLog' => true],
'second attempt logs' => ['attempts' => 2, 'shouldLog' => true],
'third attempt logs' => ['attempts' => 3, 'shouldLog' => true],
'fourth attempt skipped' => ['attempts' => 4, 'shouldLog' => false],
'ninth attempt skipped' => ['attempts' => 9, 'shouldLog' => false],
'tenth attempt logs (multiple of 10)' => ['attempts' => 10, 'shouldLog' => true],
'eleventh attempt skipped' => ['attempts' => 11, 'shouldLog' => false],
'twentieth attempt logs' => ['attempts' => 20, 'shouldLog' => true],
];
}
#[DataProvider('logSamplingProvider')]
public function testLogSampling(int $attempts, bool $shouldLog): void
{
if ($shouldLog) {
Log::shouldReceive('info')
->once()
->with(
'[HandleHubspotRateLimit] Rate limit caught, releasing job with delay',
$this->callback(static function (array $context) use ($attempts): bool {
return $context['attempts'] === $attempts
&& $context['retry_after'] === 1
&& isset($context['delay']);
})
);
} else {
Log::shouldReceive('info')->never();
}
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn($attempts);
$job->expects($this->once())->method('release');
$next = static function (): void {
throw new RateLimitException('rate limited', 1);
};
$this->middleware->handle($job, $next);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
PhpStorm
|
faVsco.js – HandleHubspotRateLimitTest.php
|
NULL
|
16968
|
|
17018
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\Middleware;
use Exception;
use Illuminate\Contracts\Queue\Job;
use Illuminate\Support\Facades\Log;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Jobs\Middleware\HandleHubspotRateLimit;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
#[CoversClass(HandleHubspotRateLimit::class)]
class HandleHubspotRateLimitTest extends TestCase
{
private const int MAX_RETRY_DELAY = 600;
private const int MIN_RETRY_DELAY = 1;
private const int JITTER_SECONDS = 5;
private HandleHubspotRateLimit $middleware;
protected function setUp(): void
{
parent::setUp();
$this->middleware = new HandleHubspotRateLimit();
}
public function testPassesThroughWhenNoExceptionThrown(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$called = false;
$next = function (object $passed) use ($job, &$called): void {
$this->assertSame($job, $passed);
$called = true;
};
$this->middleware->handle($job, $next);
$this->assertTrue($called);
}
public function testPropagatesNonRateLimitExceptions(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$next = static function (): void {
throw new Exception('Database is down');
};
$this->expectException(Exception::class);
$this->expectExceptionMessage('Database is down');
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{retryAfter: int, expectedMin: int, expectedMax: int}>
*/
public static function delayClampingProvider(): array
{
return [
'short retry uses retry_after as floor' => [
'retryAfter' => 1,
'expectedMin' => self::MIN_RETRY_DELAY,
'expectedMax' => self::MIN_RETRY_DELAY + self::JITTER_SECONDS,
],
'medium retry passes through' => [
'retryAfter' => 30,
'expectedMin' => 30,
'expectedMax' => 30 + self::JITTER_SECONDS,
],
'large retry clamped to max' => [
'retryAfter' => 86400,
'expectedMin' => self::MAX_RETRY_DELAY,
'expectedMax' => self::MAX_RETRY_DELAY + self::JITTER_SECONDS,
],
];
}
#[DataProvider('delayClampingProvider')]
public function testReleasesJobWithClampedDelay(int $retryAfter, int $expectedMin, int $expectedMax): void
{
Log::shouldReceive('info')->zeroOrMoreTimes();
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn(1);
$job->expects($this->once())
->method('release')
->with($this->callback(static function (int $delay) use ($expectedMin, $expectedMax): bool {
return $delay >= $expectedMin && $delay <= $expectedMax;
}));
$next = static function () use ($retryAfter): void {
throw new RateLimitException('rate limited', $retryAfter);
};
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{attempts: int, shouldLog: bool}>
*/
public static function logSamplingProvider(): array
{
return [
'first attempt logs' => ['attempts' => 1, 'shouldLog' => true],
'second attempt logs' => ['attempts' => 2, 'shouldLog' => true],
'third attempt logs' => ['attempts' => 3, 'shouldLog' => true],
'fourth attempt skipped' => ['attempts' => 4, 'shouldLog' => false],
'ninth attempt skipped' => ['attempts' => 9, 'shouldLog' => false],
'tenth attempt logs (multiple of 10)' => ['attempts' => 10, 'shouldLog' => true],
'eleventh attempt skipped' => ['attempts' => 11, 'shouldLog' => false],
'twentieth attempt logs' => ['attempts' => 20, 'shouldLog' => true],
];
}
#[DataProvider('logSamplingProvider')]
public function testLogSampling(int $attempts, bool $shouldLog): void
{
if ($shouldLog) {
Log::shouldReceive('info')
->once()
->with(
'[HandleHubspotRateLimit] Rate limit caught, releasing job with delay',
$this->callback(static function (array $context) use ($attempts): bool {
return $context['attempts'] === $attempts
&& $context['retry_after'] === 1
&& isset($context['delay']);
})
);
} else {
Log::shouldReceive('info')->never();
}
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn($attempts);
$job->expects($this->once())->method('release');
$next = static function (): void {
throw new RateLimitException('rate limited', 1);
};
$this->middleware->handle($job, $next);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
PhpStorm
|
faVsco.js – HandleHubspotRateLimitTest.php
|
NULL
|
17018
|
|
16958
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\Middleware;
use Exception;
use Illuminate\Contracts\Queue\Job;
use Illuminate\Support\Facades\Log;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Jobs\Middleware\HandleHubspotRateLimit;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
#[CoversClass(HandleHubspotRateLimit::class)]
class HandleHubspotRateLimitTest extends TestCase
{
private const int MAX_RETRY_DELAY = 600;
private const int MIN_RETRY_DELAY = 1;
private const int JITTER_SECONDS = 5;
private HandleHubspotRateLimit $middleware;
protected function setUp(): void
{
parent::setUp();
$this->middleware = new HandleHubspotRateLimit();
}
public function testPassesThroughWhenNoExceptionThrown(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$called = false;
$next = function (object $passed) use ($job, &$called): void {
$this->assertSame($job, $passed);
$called = true;
};
$this->middleware->handle($job, $next);
$this->assertTrue($called);
}
public function testPropagatesNonRateLimitExceptions(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$next = static function (): void {
throw new Exception('Database is down');
};
$this->expectException(Exception::class);
$this->expectExceptionMessage('Database is down');
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{retryAfter: int, expectedMin: int, expectedMax: int}>
*/
public static function delayClampingProvider(): array
{
return [
'short retry uses retry_after as floor' => [
'retryAfter' => 1,
'expectedMin' => self::MIN_RETRY_DELAY,
'expectedMax' => self::MIN_RETRY_DELAY + self::JITTER_SECONDS,
],
'medium retry passes through' => [
'retryAfter' => 30,
'expectedMin' => 30,
'expectedMax' => 30 + self::JITTER_SECONDS,
],
'large retry clamped to max' => [
'retryAfter' => 86400,
'expectedMin' => self::MAX_RETRY_DELAY,
'expectedMax' => self::MAX_RETRY_DELAY + self::JITTER_SECONDS,
],
];
}
#[DataProvider('delayClampingProvider')]
public function testReleasesJobWithClampedDelay(int $retryAfter, int $expectedMin, int $expectedMax): void
{
Log::shouldReceive('info')->zeroOrMoreTimes();
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn(1);
$job->expects($this->once())
->method('release')
->with($this->callback(static function (int $delay) use ($expectedMin, $expectedMax): bool {
return $delay >= $expectedMin && $delay <= $expectedMax;
}));
$next = static function () use ($retryAfter): void {
throw new RateLimitException('rate limited', $retryAfter);
};
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{attempts: int, shouldLog: bool}>
*/
public static function logSamplingProvider(): array
{
return [
'first attempt logs' => ['attempts' => 1, 'shouldLog' => true],
'second attempt logs' => ['attempts' => 2, 'shouldLog' => true],
'third attempt logs' => ['attempts' => 3, 'shouldLog' => true],
'fourth attempt skipped' => ['attempts' => 4, 'shouldLog' => false],
'ninth attempt skipped' => ['attempts' => 9, 'shouldLog' => false],
'tenth attempt logs (multiple of 10)' => ['attempts' => 10, 'shouldLog' => true],
'eleventh attempt skipped' => ['attempts' => 11, 'shouldLog' => false],
'twentieth attempt logs' => ['attempts' => 20, 'shouldLog' => true],
];
}
#[DataProvider('logSamplingProvider')]
public function testLogSampling(int $attempts, bool $shouldLog): void
{
if ($shouldLog) {
Log::shouldReceive('info')
->once()
->with(
'[HandleHubspotRateLimit] Rate limit caught, releasing job with delay',
$this->callback(static function (array $context) use ($attempts): bool {
return $context['attempts'] === $attempts
&& $context['retry_after'] === 1
&& isset($context['delay']);
})
);
} else {
Log::shouldReceive('info')->never();
}
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn($attempts);
$job->expects($this->once())->method('release');
$next = static function (): void {
throw new RateLimitException('rate limited', 1);
};
$this->middleware->handle($job, $next);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app, folder
.circleci, folder
.cursor, folder
.github
.sonarlint, folder
.vscode, folder
.windsurf, folder
app, sources root
Actions, folder
Component, folder
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
AiActivityType, folder
AiAutomation, folder
AiCallScoring, folder
AskAnything, folder
Dtos, folder
Events, folder
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi, folder
AWS, folder
BillingManagement, folder
Cache, folder
CoachingFeedback, folder
Country, folder
CustomerApi, folder
Database, folder
Datadog, folder
DateTime, folder
DealInsights, folder
DealRisks, folder
ElasticSearch, folder
Eloquent, folder
Encoding, folder
Encryption, folder
ES, folder...
|
PhpStorm
|
faVsco.js – HandleHubspotRateLimitTest.php
|
NULL
|
16958
|
|
16959
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\Middleware;
use Exception;
use Illuminate\Contracts\Queue\Job;
use Illuminate\Support\Facades\Log;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Jobs\Middleware\HandleHubspotRateLimit;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
#[CoversClass(HandleHubspotRateLimit::class)]
class HandleHubspotRateLimitTest extends TestCase
{
private const int MAX_RETRY_DELAY = 600;
private const int MIN_RETRY_DELAY = 1;
private const int JITTER_SECONDS = 5;
private HandleHubspotRateLimit $middleware;
protected function setUp(): void
{
parent::setUp();
$this->middleware = new HandleHubspotRateLimit();
}
public function testPassesThroughWhenNoExceptionThrown(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$called = false;
$next = function (object $passed) use ($job, &$called): void {
$this->assertSame($job, $passed);
$called = true;
};
$this->middleware->handle($job, $next);
$this->assertTrue($called);
}
public function testPropagatesNonRateLimitExceptions(): void
{
$job = $this->createMock(Job::class);
$job->expects($this->never())->method('release');
$next = static function (): void {
throw new Exception('Database is down');
};
$this->expectException(Exception::class);
$this->expectExceptionMessage('Database is down');
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{retryAfter: int, expectedMin: int, expectedMax: int}>
*/
public static function delayClampingProvider(): array
{
return [
'short retry uses retry_after as floor' => [
'retryAfter' => 1,
'expectedMin' => self::MIN_RETRY_DELAY,
'expectedMax' => self::MIN_RETRY_DELAY + self::JITTER_SECONDS,
],
'medium retry passes through' => [
'retryAfter' => 30,
'expectedMin' => 30,
'expectedMax' => 30 + self::JITTER_SECONDS,
],
'large retry clamped to max' => [
'retryAfter' => 86400,
'expectedMin' => self::MAX_RETRY_DELAY,
'expectedMax' => self::MAX_RETRY_DELAY + self::JITTER_SECONDS,
],
];
}
#[DataProvider('delayClampingProvider')]
public function testReleasesJobWithClampedDelay(int $retryAfter, int $expectedMin, int $expectedMax): void
{
Log::shouldReceive('info')->zeroOrMoreTimes();
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn(1);
$job->expects($this->once())
->method('release')
->with($this->callback(static function (int $delay) use ($expectedMin, $expectedMax): bool {
return $delay >= $expectedMin && $delay <= $expectedMax;
}));
$next = static function () use ($retryAfter): void {
throw new RateLimitException('rate limited', $retryAfter);
};
$this->middleware->handle($job, $next);
}
/**
* @return array<string, array{attempts: int, shouldLog: bool}>
*/
public static function logSamplingProvider(): array
{
return [
'first attempt logs' => ['attempts' => 1, 'shouldLog' => true],
'second attempt logs' => ['attempts' => 2, 'shouldLog' => true],
'third attempt logs' => ['attempts' => 3, 'shouldLog' => true],
'fourth attempt skipped' => ['attempts' => 4, 'shouldLog' => false],
'ninth attempt skipped' => ['attempts' => 9, 'shouldLog' => false],
'tenth attempt logs (multiple of 10)' => ['attempts' => 10, 'shouldLog' => true],
'eleventh attempt skipped' => ['attempts' => 11, 'shouldLog' => false],
'twentieth attempt logs' => ['attempts' => 20, 'shouldLog' => true],
];
}
#[DataProvider('logSamplingProvider')]
public function testLogSampling(int $attempts, bool $shouldLog): void
{
if ($shouldLog) {
Log::shouldReceive('info')
->once()
->with(
'[HandleHubspotRateLimit] Rate limit caught, releasing job with delay',
$this->callback(static function (array $context) use ($attempts): bool {
return $context['attempts'] === $attempts
&& $context['retry_after'] === 1
&& isset($context['delay']);
})
);
} else {
Log::shouldReceive('info')->never();
}
/** @var Job&MockObject $job */
$job = $this->createMock(Job::class);
$job->method('attempts')->willReturn($attempts);
$job->expects($this->once())->method('release');
$next = static function (): void {
throw new RateLimitException('rate limited', 1);
};
$this->middleware->handle($job, $next);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app, folder
.circleci, folder
.cursor, folder
.github
.sonarlint, folder
.vscode, folder
.windsurf, folder
app, sources root
Actions, folder
Component, folder
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
AiActivityType, folder
AiAutomation, folder
AiCallScoring, folder
AskAnything, folder
Dtos, folder
Events, folder
AskAnythingPromptService.php, class
HistoryService.php, class
AskJiminnyAi, folder
AWS, folder
BillingManagement, folder
Cache, folder
CoachingFeedback, folder
Country, folder
CustomerApi, folder
Database, folder
Datadog, folder
DateTime, folder
DealInsights, folder
DealRisks, folder
ElasticSearch, folder
Eloquent, folder
Encoding, folder
Encryption, folder
ES, folder
Faker, folder
FeatureFlags, folder
FFMpeg, folder...
|
PhpStorm
|
faVsco.js – HandleHubspotRateLimitTest.php
|
NULL
|
16959
|
|
15969
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
namespace Jiminny\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Foundation\Bus\Dispatchable;
abstract class Job
{
/*
|--------------------------------------------------------------------------
| Queueable Jobs
|--------------------------------------------------------------------------
|
| This job base class provides a central location to place any logic that
| is shared across all of your jobs. The trait included with the class
| provides access to the "onQueue" and "delay" queue helper methods.
|
*/
use Queueable;
use Dispatchable;
protected bool $dispatchJobSync = false;
public function setDispatchJobNow(bool $dispatchJobSync): self
{
$this->dispatchJobSync = $dispatchJobSync;
return $this;
}
protected function dispatchJob(self $job, ?string $queue = null): void
{
$job->setDispatchJobNow($this->dispatchJobSync);
if (! $this->dispatchJobSync) {
if ($queue !== null) {
dispatch($job)->onQueue($queue);
return;
}
dispatch($job);
return;
}
dispatch_sync($job);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
PhpStorm
|
faVsco.js – Job.php
|
NULL
|
15969
|
|
15970
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
namespace Jiminny\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Foundation\Bus\Dispatchable;
abstract class Job
{
/*
|--------------------------------------------------------------------------
| Queueable Jobs
|--------------------------------------------------------------------------
|
| This job base class provides a central location to place any logic that
| is shared across all of your jobs. The trait included with the class
| provides access to the "onQueue" and "delay" queue helper methods.
|
*/
use Queueable;
use Dispatchable;
protected bool $dispatchJobSync = false;
public function setDispatchJobNow(bool $dispatchJobSync): self
{
$this->dispatchJobSync = $dispatchJobSync;
return $this;
}
protected function dispatchJob(self $job, ?string $queue = null): void
{
$job->setDispatchJobNow($this->dispatchJobSync);
if (! $this->dispatchJobSync) {
if ($queue !== null) {
dispatch($job)->onQueue($queue);
return;
}
dispatch($job);
return;
}
dispatch_sync($job);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
PhpStorm
|
faVsco.js – Job.php
|
NULL
|
15970
|
|
16095
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
declare(strict_types=1);
namespace Jiminny\Exceptions;
use Throwable;
class RateLimitException extends RuntimeException
{
public function __construct(
string $message = '',
private readonly int $retryAfter = 1,
?Throwable $previous = null,
) {
parent::__construct($message, 0, $previous);
}
public function getRetryAfter(): int
{
return max($this->retryAfter, 1);
}
}...
|
PhpStorm
|
faVsco.js – RateLimitException.php
|
NULL
|
16095
|
|
15968
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Foundation\Bus\Dispatchable;
abstract class Job
{
/*
|--------------------------------------------------------------------------
| Queueable Jobs
|--------------------------------------------------------------------------
|
| This job base class provides a central location to place any logic that
| is shared across all of your jobs. The trait included with the class
| provides access to the "onQueue" and "delay" queue helper methods.
|
*/
use Queueable;
use Dispatchable;
protected bool $dispatchJobSync = false;
public function setDispatchJobNow(bool $dispatchJobSync): self
{
$this->dispatchJobSync = $dispatchJobSync;
return $this;
}
protected function dispatchJob(self $job, ?string $queue = null): void
{
$job->setDispatchJobNow($this->dispatchJobSync);
if (! $this->dispatchJobSync) {
if ($queue !== null) {
dispatch($job)->onQueue($queue);
return;
}
dispatch($job);
return;
}
dispatch_sync($job);
}
}
Sync Changes
Hide This Notification
Code changed:
Hide
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Project
Project
New File or Directory…
Expand Selected
Collapse All...
|
PhpStorm
|
faVsco.js – Job.php
|
NULL
|
15968
|
|
16912
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
FinderFileEditViewGoWindowHelp•00DEV (docker)DOCKERO ₴1DEV (docker)882APP (-zsh)|• жзmasterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ devroot@docker_lamp_1:/home/jiminny# ]labol# Support Daily - in 2 h 19 m-zsh84-zsh885100%8• Mon 11 May 12:41:051881screenpipe"O 86DEV...
|
PhpStorm
|
faVsco.js – SyncCrmEntitiesTrait.php
|
NULL
|
16912
|
|
16404
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Firefox FileEditViewHistoryBookmarksProfilesToolsWindowHelpDOCKER881DEV (docker)882APP (-zsh)DEV (d)• хз.masterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-Lirroot@docker_lamp_1:/home/jiminny# ]•HomeDMsActivityFilesLater..•Moreal]Support Daily • in 3 h 11 m100% <78• Mon 11 May 11:49:04ED→Describe what you are looking forJiminny ...Stefka Stoyanova6 0Cnsmechuus# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...7 Untitled+0 Direct messagesa. Stefka Stoyanova€. Vasil VasilevNikolay Ivanov®. Galya DimitrovaAneliya Angelova, .... Stoyan TanevVes®. Aneliya Angelova& James GrahamE Lukas Kovalik y...:: AppsJira Cloud• MessagesC Files@ UntitledLukas KovalK k-44 PMблагодаряTuesday, April 28th~Today ~Stefka Stoyanova 10:08 AMЛукаш, щом пре-рефайнмънта и рефайнмьнтаще са само за МСР ако искаш не идвай да сигубиш времетоLukas Kovalik 10:12 AMда, няма да идвамStefka Stoyanova 11:35 AMЛукаш, ще сложиш ли естимейт наhttps://jiminny.atlassian.net/browse/JY-20818Jira Cloud -Move Ask Jiminny reports to separate...Bug JY-20818 in Jira CloudStatusDeployedPriority= MediumAssigneeLukas Koval...As of today at 11:35 AMOpen in JiraSummariseLToastMessage Stefka StoyanovaGoogle Cale.........
|
PhpStorm
|
faVsco.js – RateLimitException.php
|
NULL
|
16404
|
|
15436
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
FirefoxFileEditViewHistoryBookmarksProfilesToolsWindowHelplah|meet.google.com/mie-gawc-dsi?authuser=[EMAIL] Yankov (Presenting)Daily - Platform - now100% LMon 11 May 9:50:099+•SC Jy 20451 Servic83 Jmier8 Promohttps://fiminny.atlassian.net/jira/software/c/projects/JY/boards/37?selectedissue=JY-20566D Projects23 SSHPlatform Team %.Q Search board20€A.J Panorama for CallScoring n ou(AUTOMATED AT SGORINGKedoy torDoyA Jy-2030125 **** = $Setup test coverage forProonorioherMASNTENANCISBacklogE 3-109511****= 3O: AttentEa DatadogCalsCa Transp3 CircleCi|SentryX MCP*xI0 DerMon 11 May 9:50• appіo|L Al BookmarxsGroup: QueriesAI Reports > Empty pagedesign and promotonAJREPORTSDeployed0 -20372 1 П •** = |Grok via AzureMAINTENANCEDeployedД -207261 @ •++•=Allow users to delete SSand Panorama promptswhen those are used in a...AJREPORTSDeployed0E -20770 / 12 ..*0 =Release AJ PanoramaDeployed0 -20740 05 12 •***=Wrong formatting forsummary in the CRMMASNTENANCENikolay IvanovNikolay Yankov4 othersAneliya Angelova9:50 AM | Daily - PlatformLộ3Lukas Kovalik1:42...
|
PhpStorm
|
faVsco.js – Client.php
|
NULL
|
15436
|
|
15216
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
PhostormFV faVsco.jsVIewINavicareCode%9 JY-20725-handle-HS-search-rate-limit-Proletey© BatchSyncCollectore balchsynckealsse© HubspotSyncStrategyBase.phpCachedcrmservicebecorator.pnp© ProspectCache.phpo closedDealstagess© MatchactivityermData.png© CrmActivityService.phgDealrielasservice.gc)Decorateacuivilv.or© FieldDefinitions.phpC) FieldT vpeconvertee Hubspotclientinterc) Hubspotlokenman© PayloadBuilder.phpC) Remotecrmobiectr© ResponseNormalizec) Service.ono© SyncFieldAction.phC) SvncRelatedActivitC) WebhookSvncBatclv MintearationAorM Acceccors745ConfigODTOD FiltersJobsD ProspectSearchStra747W service Iralts© DataClient.phpMEREEERES// "110"Sremaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'):"109"$interval= Sresponse->getHeaderLine("X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"$bodyjson_decode((string) $response->getBody(),true);\Illuminate|Support\Facades\Log: :channe2('custom_channel')->info('$max ' . PHP_EOL • print_r($max, F$23(\Illuminate|Support\Facades\Log: :channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($t24\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$intervalPHP_EOL print_r($ir25\Illuminate|Support\Facades\Log: :channel('custom_channel')->info('$body ' . PHP_EOL • print_r($body, 26© DecorateActivity.pr© LocalSearch.phponlirhrocatalnreou Localsearchinteria© RemoteSearch.php757c) Service.phpv W Listeners758759© ConvertLeadActivitc) PurceLookuocache› D Metadata762 €> MiarationPipedrivev Salesforce• D FieldsM OnnortunitvMatcheOpportunitySyncStrM ProsneetSearchStr.Service TraitsC) Client nhr© DecorateActivity.pt. Delete@biectsTrait© FieldDefinitions.php© PayloadBuilder.php© Profile.php© QueryBuilder.phpclass Client extends BaseClient implements HubspotClientInterfaceA2 A65 X1X1Aoubuc tunction makerequest strina sendooint.terienet eo e, Spoyload - (1, 2etrng Seuaryerng 1 m)Sresponse = $this->getInstanceO->getClientO?->request(enapoinc. senapolncquery scrino: squeryscrino7 else {Sresponse = sthis->getinstanceo->qetclento->requestsmethod, sendpoint."ason' => (spavload)=30=31* acnrows badkequest*acnrows nuospoccxceptlonpublic tunction createMeetingarray Spayload: ResponseSendpoint = "crm/vs/ob1ects/meetings'method:"Post', soavload)"* athrows HubsnotExcentionnubidic Function undateMeetinalstrina Smeptinaid, arnav Snavinad)• RecnonseSendpoint = '/crm/v3/objects/meetings/' . SmeetingId;return $this->makeRequest($endpoint, method:'PATCH', $payload);lelper Code will help IDE to understand your Laravel app code. // Generate // Don't Show Anymore (19 minutes ago)Dally - Platrorm • In 1oh100% 2&• Mon 11 May 9:27:44L AskJiminnyReportActivityServiceTest ~+0 ..A SF jiminny@localhost]A HS_Jocal (jiminny@localhost]Cascade# console [PKob.# console [euJ# console [slAGiNG)Hubspot Rate Limit Re[2026-05-07 14:21:15] Local. INFO: [Hubspot] DEBUG Getting headers {MMi9.У9. Matchcrmbata rate limiter move is logically correct but asymmetric with the quard"neaders".?MatchCrmData.oho:103-11k"Uace":L"Inu,or May 2020 14.21.15 6Ml"Jn"Transter-Encod1nq":"chunked").if (! $rateLimiter->canMakeRequest(Sactivity->getCrmO))) {sthis->release(..)return;"CF-Ray":L"9t80debödb60dcsa-S0F"J,"Strict-Transport-Secur1ty":"max-aqe=31536008* 1ncLudeSubDomains: preload")n"Vary": ["origin,accent-encodino""access-control-allow-credentials": ["false"],"server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",ScrmObjects = $crm0bjectsResolver->resolveFromCall(...):SrateLimiter->incrementRequestCount(Sactivity->getCrm());Movina increment:RequestCount to after resolveFromCall is correct — previouslv it counted the attemot even if the call failed. However. resolveFronCall canmake multiple CRM API calls (email match + phone match + domain match). The rate limiter counts this whole resolver as 1 request. If a preventive rate limiter wereadded inside Client, the ProviderRatelimiter at the job level would count "1 request" while the client made 3 calls — so the two counters would diverge and thepreventive limiter would still be meaninaful independentlv."x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtmOY-1778163675-[IP_ADDRESS]-May-26 14:51:15 GMT; domain=.hubapj.com; Http0nly; Secure; SameSite=None"],"Report-To" : ["(\"endpoints\": I\"urz\":\"https:|\\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RW\"group\" :\"cf-nell",\"max_age\":604800}"],"NEL" : ["{\"success_fraction\":0.01,\"report_tol":\"cf-nel\",\"max_age\":604800}"],"Server": ["cLoudflare"]H} {"correlation_id": "95236535-ec98-4541-b92a-adfa73b69eab","trace_10":"C/AD8565-905t-4604-9405-0e5b551e5545hRate Limit counter Interaction — vatchcrnbata vs Cllent-Side Preventive LimitThe question about how the ProviderRateLimiter would interact with a preventive client-side rate limit:Current flow (MatchCrmData):1. canMakeRequestlo checks the Laravel cache-oased counter + 1ob-level, coarse-arained, oer-cRM-contic2. resolveFromCall() makes 2-3 actual HubSpot API calls3. incrementRequestCount () adds 1 to the counterIf a preventive rate limit were added in Client (e.g. before search()):• It would be a per-second/per-10s Redis/cache token-bucket - much finer grained• The job-level ProviderRateLimiter operates at a completely different granularity (its quota and window are defined by the CRM getRateLimits()configuration)• They would operate independently and in parallel - which is correctThe current client-side rate limiting is reactive only (catches 429 → throws RateL.imitException → middleware re-queues). There is no preventive client-sidebucket. A preventive approach would look like: before executeRequest (), check a Redis token bucket and sleep/throw proactively if the rate would be exceeded.This areadv exists for the loblleve lbut no lnside the!TP ciient. The PadinatilonConfiin::SFARCH RPSITMIT-4.andLusileen(Kdellav)inHmbsnotDannatalonServte is the only existing preventive mechanism, but it only applies to paginated searches, not to individual search() calls made from Service. php methods.Summary TableSeverityIssue• Serious• Serious• Serious• MinorsearchcallsForPer1od* searchCallByRecordingURLToken swallow RateLimitException as generic ExceptionMatchActivityCrmData middleware mostly ineffective - getContactByEmai1 path bypasses executeRequest ()batchReadobiects 429s are eaten and rethrown as Crmexception, not RateL1m1tExcept1onisHubspotRateLimit for GuzzleHttp\RequestException checks wrong code (exception code vs HTTP status)Commented-out debug code and dead code in makeRequest () and getOpportunityById()ФAsk anvthing (84.L)+ <> CodeC° AdantiveW Windsurf Teams 748:17 (59 chars, 1 line break) UTF-8f?4 spaces...
|
PhpStorm
|
faVsco.js – custom.log
|
NULL
|
15216
|
|
16567
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
PhostormINavicare© TrackRecordingFileSiz© TrackRecordingSizeEnT. ValidateSmitProspect:AjReports0 CalendarConference0 Crm@ bullnorn> OJ CloseC Copper>J Crmobiects07 DecorateActivitv• DummyHelpersv h HubspotAccountSvncStrate> Actionsa ContactsvncStraterFields• Malournal1 Metadatalv OpportunitySyncSt• M Concerns.(c) Hubsnotl actMoC HubspotLastMo(C) Hubsnotl actMo(C) Hubsnotl actMo(C) Hubsnotl actMo(C) HubsnotSinaleSo UnhenotCunaCtrC Huosporweonoov _ Paginationc) huosporpacinal© PaginationConfi(C) PaqinationState> D ProspectSearchStr:› D Redisv D ServiceTraitsTOnoortunitvsvnc() SvncCrmEntitiesT SuncFieldstirait.T. WriteCrmTrait.o• M UtilsM WebhookcodeFV faVsco.jsroledeyC) BatchSvncCollectot(c) RatchSvncRedisSec) Client nhr(C) ClocedDea|Stadecs@ DoalFieldsService r© SyncRelatedActivityManager.php© ProspectCache.phpCrmacuivityservice.ong*RateLimitexception.php(C) ProviderRateLimiter.phpC) PaqinationConfia.phpclass Cuient extends BasecLient imolements Hubspotcuientinterface* dtemolate 7* dparam callableo: T Saoicalt* areturnT* Othrows RateLimitExceptionnrivate function executeRequestcallahle SanicallalScacheKey = $this->getRateLimitCacheKeyO:ScachedRetrvAfter = Cache: :aet(ScacheKev)•14 Gs_int(ScachedRetrvAfter)) <ScachedRetrvAfter = Redis::aet(Scachekev):if (is string(ScachedRetrvAfter) &s is numeric(ScachedRetrvAfter)) {'Hubspot rate limit (cached circuit-breaker)'.int) ScachedRetnvAftentry freturn $apiCallo:} catch (Throwable $e) {if (Sthis->isHubspotRateLimit(Se)) {SretryAfter = Sthis->parseRetryAfter(Se):Cache::put(ScacheKey, $retryAfter, SretryAfter);Redis::setexScacheKev. SretrvAfter. (string) SretrvAfter)Sthis->l00->warning('[Hubspotl Received 429 from APT'. f= Sthis->confia->aetido.Inetny aftenl => SnetrvAften.Inolicv= Sthis->nancePolicv(Se)Inpason.= Se->aetMeççane@.spot returned 429', SretryAfter, $e);Accept Reiect=19=21=24= custom.loa XA SF (jiminny@localhost]4 HS_local (jiminny@localhost]# console [PKOb.# console leu)# console [slAGiNg).2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {headers'1"Vace". "Inu,ur May 2020 14.21.19 6Ml"Jn"Concent-lvoe". "apolicacionison charser=utt-on"Transfer-Encoding": ["chunked"]."CF-Ray": ["9f80deb8db60dc3a-SOF"]."CF-Cache-Status": L"DYNAMIC"J,"Strict-Transport-Secur1ty":"max-aqe=31536000* 1ncludeSubDomains: preload")acceot-encodino"."access-control-allow-credentials": "false"."server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfr;desc=|"9f80deb8e7c6dc3a-IAD\""],"x-content-tvoe-ootions":"nosniff"."x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"Set-Cookie":["__cf_bm=StUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Report-To":["{"endnoints".("url\":"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RV("group\":\"cf-nel\",("max_age\":604800}"],"NEL":["{"success_fraction\":0.01,"reportco. "cr-nel"max agel ":604800}"].'Server": ["cloudflare"]}} {"correlation_1d":"95256555-ec98-4541-b9za-adta/Sboyeab","trace_10":"C/AD8565-905t-4604-9405-0e5b551e554540• suppont Dally • In Zn 04m100% Lz• Mon 11 May 12:06:25AskJiminnyReportActivityServiceTest vCascade0 HubSpot Rate Limi+0 ..• Client.php+5 -5Dirterences: Cache::qet VS Redis::qeth ohoBeforeScachedRetryAfter = Cache::get($cacheKey); // returns mixed (deserialized PHP value)if (is int(ScachedRetryAfter)) ‹ ... }Cache: :put($cacheKey, $retryAfter, SretryAfter);internally: sel cache_prerax: Larave l_cache-nubspot: rate tamat:portal:42 - "2i2;" (PHP Serzatazea)EXPIRE on the same key$cachedRetryAfter = Redis::get($cacheKey);// returns string|false|nullt us string scachedRetrvAtter ve 1s numericScachedRetrvAtter) ...?Redis::setex($cacheKey, SretryAfter, (string) SretryAfter):// Single atomicKey imolementation notes1. SETEX is atomic - sets the value and TTL in one round-trip. Cache: :put internally does this too, but adds prefix manipulation and serialization in PHP-land2. No prefix from Laravel cache confia. Your key in Redis will be exactiv hubspot:ratelimit:portal:42, not cache prefix:laravel cache:hubspot:ratelimit:portal:42 . Easier to inspect with redis-cli . Make sure no other code is using a key like that - unlikely with this namespace3. Return value handlina• Redis::aet (Snonexistent) → returns null (Predis) or false (PhoRedis)• The is strina(sy) f6 fs numeric(sy) quard handles both cases nlus malformed values cleanlv.4. Connection: uses Laravel's default Redis connection ( config/database.php redis.default ). If you want to isolate this from queue/cache traffic, use Redico•connection("rate linitci)_saet(...) after definina a senarate connection5. Type cast (string) on store: setex requires a string value. Without the cast, PhpRedis throws a TypeError on intPerformance deltaCache:aet/outRedis.aet/setexRound-trips1 (combined)PHP CPU per on~50-100us (CacheManager + serialize)~10-20us (direct Redis cmd)Network bytes (value)~10 bytes (1:1: )1 byte (("1")Key lenath~50 chars (with prefix)~30 charsNealidible per-call. but at 1.500 cache GETs/sec (steadv state from orevious trace).aon/Services/Crm/Hubsoot/mClient.oho +5 -5Ask anvthina (&4L)+ « CodeClaude Onus 4.7 MediumView allReiect alllAccent alliW Windsurf Toams 81-16 UTF.9io 4 spaces...
|
PhpStorm
|
faVsco.js – Client.php
|
NULL
|
16567
|
|
15250
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
PhostormVIewINavicareCodeFV faVsco.js°9 JY-20725-handle-HS-search-rate-limiProiect v© BatchSyncCollectolyhuospotsyncstrategybase.ongCachedcrmservicebecorator.pnp© ProspectCache.phpe balchsynckealsseС Cпескапокetrукemotematch.ongccloseaDealstagess @ MatchacuivitycrmData.ong© CrmActivityService.phgDealrielasservice.gc)Decorateacuivilv.or© FieldDefinitions.phrC) FieldT vpeconvertee Hubspotclientinterc) Hubspotlokenman© PayloadBuilder.phpC) RemotecrmobiectrP ResponseNormalizec) Service,onoC)SvncFieldAction.onC) SvncRelatedActivitC) WebhookSvncBatclv MintearationAorM AcceccorsConfigD DTO• M SiltersJobs. M ProspectSearchStrW service lralts© DataClient.php© DecorateActivity.ph© LocalSearch.phpu Localsearchinteria© RemoteSearch.phpc) Service.phpv W Listeners© ConvertLeadActivitc) PurceLookuocache> M Metadata> Miarationia Pioedrivev Salesforce• D FieldsM OnnortunitvMatcheMOnnortunitvSvneStM ProsneetSearchStr.• M ServiceTraitcC) Client nhr© DecorateActivity.ph. Delete@biectsTrait© FieldDefinitions.php© PayloadBuilder.php© Profile.php© QueryBuilder.phpclass Cllent extends Baseclient 1mpLements Hubspotclientintertaceis crte t axtenn tAsoint onsTeta tae au stote tentin eranl birct eficin Stolhitar) A 1A42 465 ×1 M1 A9789899971AA6sassoclaclonbaca =SidChunks = array_chunk($ids,length: self::ASS0CIATIONS_BATCH_SIZE_LIMIT):foreach (SidChunks as SidChunk){trySbatchinout = new Hubspot.Clrent.crm.Associations Model BatchinoutPubl1c0bnectidolSbatchInput->setInputs(array_map(function (Sid){Spubuncobnectid=HubSpot Cllent Crm Associations Model PublacubnectidorSpublic0bnectiid->setidS1d):return $publicObjectid;SidChunka)SassociatedObiectsData = Sthis->getNewInstance®->crmol=23-Saccociationsol-ShatchAni0l->npad(sfromßhiect Stoßhiect ShatchTnnut)•if (Sassociated0bjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePubl:28foreach (Sassociated0bjectsData->getResults as $association){$from = Sassociation->getFrom->getIdO:$toAssociations = Sassociation->getTo@:—31if (! empty(StoAssociations)) {SassociationData[Sfrom] = array_map(function (Sitem) {return Sitem->qetidor.Stoassoclatlons)catch ateLimitExcention Se) <Ithrow $e;} catch (\Excention $e) {Sthis->loa->error('[Hubspotl Failed to fetch associations'. "'from obiect' => Sfrom0biect.I MT 1ito nhiecti => Stolhrect..Irpason' => Se->aetMecsane01141PIlelner Code will hoin INF to underctand vour Laravel ann code II Generate II Don't Show Anvmore (25 minutes aao)=custom.log~=laravel.logA SF (jiminny@localhost]4 HS_local (jiminny@localhost]# console [PKOb.# console leu)# console [slAGiNg)[2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"neaders".?"Uace":L"Inu,or May 2020 14.21.15 6Ml"Jn"concenc-lyoe. apolicacionison.charser=utt-on"Transter-Encod1nq":"chunked")."Connection":"keep-alive""CF-Ray":L"9t80debödb60dcsa-S0F"J,"Strict-Transport-Secur1ty":"max-aqe=31536008* 1ncLudeSubDomains: preload")n"Vary":"orioin.accent-encodino""access-control-allow-credentials": ["false"]."server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\","x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"So+-Cookie"." c+hm-Stlirtd0aXVr.kSandas6hzVVKhzTn0BidvMaheCtmoV-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Report-To":["{"endpoints\":[{"unl".httns:la.nel.cloudflane.com./renon+W/v42c=NVA1cVTPQfVm32anS0#xVF/sd2RN\"group)":\"cf-nel\","max_age\":604800}"],"NEL":["{\"success_fraction\":0.01,"report to":|"cf-nel\"."max age":604800}"]"Server": ["cloudflare"]}} {"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab""trace_10":C/AD8565-905t-4604-9405-0e5b551e5545"Dally - Platrorm • In 12m100% 47 • Mon 11 May 9:33:43AskJiminnyReportActivityServiceTestvCascadeHubspot Rate Limit Re+0 ..not cache exceptions, but the exception will propagate up uncaught past anything expecting find() to return an array). Any caller of find() (the CRM prospectsearch usea in the ulextension will get an unnandled exception. Inis is Inconsistent with the intent — those callers don t nave hand LenuospotkateLImitmiddleware2. searchCallsForPeriodByPage/searchCallsForPeriod/searchCallByRecordirAll three catch Exception• Service.php:1584} catch (Exception $exception) ‹RateLimitException extends LoqicException which extends Exception? Let me verity:Searched class LogicException in app/Exceptions/LogicException.php (2)RateLimitException extends LoqicExcept ion extends \LoqicException extends \Exception. So all catch (Exception se) blocks in Service. oho will swallow theRateLimitException - rate limit events are silently treated as call-not-found and processing continues, losing the ability to back off. This includes:• searchCallsForPeriodByPage → calls sleep(1) and retries once with no back-off awareness• searchcal BvRecordinaURLToken → same oattern• The do-while loop in getCalls() (line 1561) - continues to next page as if the page returned emptySerious3. MatchActivityCrmData has HandleHubspotRateLimit middleware but the actual CRM call path may not throw RateLimitExceptionMatchAct.ivityCrmData calls crmActivitvService=>updateCrmData.which eventually calls.matchFxactivBvFmail0→ [EMAIL] method doesnot go through executeRequest () - it uses the SDK directly with no rate limit wrapping:#Client.php:503-523publac tunctzon getContactByEmail(string semail, array sfields = (l): arraytry{Scontact = Sthis->aetNewInstance()->crm()->contacts()->basicApi()→>aetBvId(...)The middlewarelis attachedlbut.theunder.vina.nath doesnltnronadateRatelEimiltExcentaion/for.thatmethodwtwillionvfirelf.somethina.alona.the.wavuses.exe.cuit4. getAssociationsData catches RateLimitException and re-throws it - but the wrapped catch (\Exception $e) that follows would still catch it before there-throwitthe order were dititerent. Orderis currentiv correct but the separate re -throw onkaite mim ti xcen sioni s redundant bol erolate since the next catchiis\Exception - the intent is correct but it means callers of getAssociationsData will get a RateLimitException thrown without the HandleHubspotRateLimit5. batchRead0bjects calls $this->ensureValidToken() but does NOT go through executeRequest ()#Client.php:282-293Sthis->ensureValidToken():try 1Sresponse = SbatchConfial'api'->read(SbatchReadRequest):A 429 from the batch API will throw a DealApiException / ContactApiException etc., but since batchReadObjects wraps in handleBatchError() which rethrows asCrmException — the RateLimitException will never be raised for batch operations. This is inconsistent with search(), where 429 - RateLimitException• Minor / ImprovementsWN Windsurf Teams052-74io 4 spaces...
|
PhpStorm
|
faVsco.js – Client.php
|
NULL
|
15250
|
|
16343
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
PhostormVIewINavicareCodeFV faVsco.js°9 JY-20725-handle-HS-search-rate-limiProiect( OutofRoundsEycention n.yhuospotsyncstrategybase.ongQuotaExceededExceptiorKateLimitexception.onp© RegistrationinvitationMisr© RequestQueuedForDeferrResponseException.phpRinqCentralException.phr © PaginationConfig.phpRingcentralExtensionNotlrohoRuntimeException.php( SequenceNumberExceptideclare(strict tvoes=1)):@ ServicelntegrationExcept( ServiceUnavailable Excepnamespace Jiminny Excentions:( SidekickSettinosexceotio(4 Socia Account NotFoundeluse Throwahile:(4) SocialAccountTokeninvali(SvncActivitvExcention.ohclass Ratel imi+Fxcention extends RuntimeSxcentionf TenantisolationEyception.( TextRelavsxcention.ohv@ TooManvFailedActivities 1 12public function __construct(string smessage -4 TranscrintionNotindeyedi 12private readonly int SretryAfter = 1,@ UneynectedCallSycention 17cInrowable sprevious = null.© UnexpectedEloquentMod 15© UnexpectedValueExcepti 16parent:: constructsmessage.code: 0, Sprevious© ZipAttackException.phpD FFMpegD) Formats> D Guardspublic function getRetryAfterO: intCacando 99 1=1• m Helpersv D Httpreturn maxsthis->retrvatter..values: "• _ AccessI okenProviderv C Controllersv DAPI> 0 AiCallScoringAlReports• DeallnsiantsOoportunit• → PaqeScorecards• SettinasTeaminsiahts• M Themecv MUserAutomatedRer(C) UserAutomatedivMv2C) ActivitvV2Contr8) AckAnvthinaGor(C) Ack liminnvRend( NonleV2Controll(e OnNemandv2e,0 DievlictControlle"a) DiaulictCharoCoolner Code will hoin INF to underctand vour Laravel ann code II Generate II Don't Show Anvmore (todav Q•08)© SyncRelatedActivityManager.phpCachedcrmservicebecorator.ong© ProspectCache.phpC) HandlerubspotkateLimit.php xommand 9esuppont Dally • In sh 1om100% 2• Mon 11 May 11:44:09AskJiminnyReportActivityServiceTest v+0 ..= custom.loa XA SF (jiminny@localhost]4 HS_local (jiminny@localhost]# console [PKOb.# console [euJ# console [slAGiNg)2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {headers'1"Vace". "Inu,ur May 2020 14.21.19 6Ml"Jn"concenc-lyoe. apolicacion/ison.charser=utt-on"Transfer-Encoding": ["chunked"]."CF-Ray":"9t80deb8dbo0dcsa-SOF","CF-Cache-Status": L"DYNAMIC"J,"Strict-Transport-Secur1ty":"max-aqe=31536000* 1ncludeSubDomains: preload")acceot-encodino""access-control-allow-credentials": "false"i."server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfr;desc=|"9f80deb8e7c6dc3a-IAD\""],"x-content-tvoe-ootions":"nosniff"."x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"Set-Cookie":["__cf_bm=StUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Report-To":["{"endnoints".("url\":"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RV("group\":\"cf-nel\".("max_age\":604800}"],"NEL":["{"success_fraction\":0.01,27"reportco. "cr-nel"max agel ":604800}"].'Server": ["cloudflare"]}} {"correlation_1d":"95256555-ec98-4541-b9za-adta/Sboyeab","trace_10":"C/AD8565-905t-4604-9405-0e5b551e5545CascadeHubspot Rate Limit Reb phpcatch (Throwable se) ‹if (! $e instanceof RateLimitException) {Log::error('(MatchActivityCrmData] Failed to match CRM data', [...]):throw se:Same outcome, more readable, no dead-looking throw se branch.molementing all three chandes•RateLimitException.php• Client.php+7-12Now the middleware — droo DAILY LIMIT branch. drop MIN RETRY DELAY to 1. keen litter."HandleHubspotRateLimit.oho+3 -13Now MatchActiv1tycrmbata - collapse the two catches into one with instanceot:•MatchActivityCrmData.php+8-8|All changes applied. Final state:Summary of this round of changesFileChangeReasonRateLimitExcent.ion.ohrRemoved policy field & methodsMiddleware doesn't need it: cache TTL handles DAILY naturallvCLient. oho:: executeRequesCache stores scalar fint (retry after) instead of arravSimoler. no policy to trackCLient. oho:- executeRequesDroo policy from RateLimitExcent ion constructonMatch new excention sianature: still loa policy for observabilitvHandleHubspotRateLimit.phpretrvUntil + lona cache TTL handle it. saves comolexitvHandleHubspotRateLimit.phpHonor HubSoot's actual sianal: litter does the herd orotectionHandleHubspotRateLimit.ohdNamed JITTER SECONDS constantSelf-documentingCollapsed dual catch into sinale catch + instanceofMore readable: no awkward empty rethrow blockHow DAILY LIMIT now flows (no special case needed)1. HubSpot returns 429 with policvName: DAILY LIMIT2. parseRetryAfter sees no Retry-After header, falls through to policy table → returns 600s (the DAILY_LIMIT default I left in parseRetryAfter)3. Cache populated with TTL=600 (10 min)4. All subsequent requests fast-fail via cache for 10 min - no API calls5. Middleware releases jobs with delay 1-6s (cheap cycles, all hit cache)6. After 30 min. retrvüntil expires → iobs permanent-fail naturallv7 No cnecial branch no cioh-sfasll) no eycontion field3 files +73 -43Reiect allAccent alliAsk anvthing (84.L)Claude Onus 4.7 MediumW Windsurf Teams19-24 (12 charc)UTE.Rio 4 spaces...
|
PhpStorm
|
faVsco.js – HandleHubspotRateLimit.php
|
NULL
|
16343
|
|
15282
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
PhostormVIewINavicareCodeFV faVsco.js°9 JY-20725-handle-HS-search-rate-limitProiect© BatchSyncCollectolyhuospotsyncstrategybase.ongCachedcrmservicebecorator.pnpe balchsynckealsseo closedDealstagess)MatchactivitycrmData.ong© ermactivilyservice.phgDealrielasservice.gc)Decorateacuivilv.or© FieldDefinitions.phrC) FieldT vpeconverteclass Cllent extends Baseclient 1mpLements HubspotclientintertaceGL1e Funetion etassoclationsData (ar rey stot sentin erromobiect, string Stodbiet) : array42 465 ×1 M1 лe Hubspotclientinterc) Hubspotlokenman© PayloadBuilder.phpC) RemotecrmobiectrP ResponseNormalizec) Service,onoC)SvncFieldAction.onC) SvncRelatedActivitC) WebhookSvncBatclv MintearationAorM AcceccorsConfigD DTO• M SiltersJobs. M ProspectSearchStraW sevice lraits© DataClient.php© DecorateActivity.ph© LocalSearch.php978u Localsearchinteria© RemoteSearch.phpc) Service.phpv W Listeners© ConvertLeadActivitc) PurceLookuocache> M Metadata> MiarationiM Pipedrivev Salesforce• D FieldsM OnnortunitvMatcheMOnnortunitvSvneSt991M ProsneetSearchStr.) M ServiceTraitcC) Client nhr© DecorateActivity.ph. Delete@biectsTrait© FieldDefinitions.php© PayloadBuilder.php© Profile.php997© QueryBuilder.php1AA6sassoclaclonbaca =SidChunks = array_chunk($ids, length: self::ASS0CIATIONS_ BATCH_SIZE_LIMIT):foreach (SidChunks as SidChunk){trySbatchInout = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublic0biectIdoSbatchInput->setInputs(array_map(function (Sid){Spubuncobnectid = newHubsoot Client Crm Associations Model Publacobnectido:Spublic0bnectiid->setidS1d):return $publicObjectid;}, $idChunk));SassociatedObiectsData = Sthis->getNewInstance®->crmol=23-Saccociationsol-ShatchAni0l->npad(sfromßhiect Stoßhiect ShatchTnnut)•if (Sassociated0bjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePubl:28foreach (Sassociated0bjectsData->getResults as Sassociation) {$from = Sassociation->getFrom->getIdO:$toAssociations = Sassociation->getTo@:—31if (! empty(StoAssociations)) {SassociationData[Sfrom] = array_map(function (Sitem) {return Sitem->qetidor.Stoassoclatlons)} catch (RateLimitExcention $e) {throw $e;} catch (\Excention $e) {Sthis->loa->error('[Hubspotl Failed to fetch associations'. f'from obiect' => Sfrom0biect.ito nhiecti => Stolhrect.Irpason' => Se->aetMecsane01lelner Code will hoin INF to underctand vour Laravel ann code II Generate II Don't Show Anvmore (22 minutes aaolhel1Daily - Platform - in 5 m100% (. • Mon 11 May 9:40:22AskJiminnyReportActivityServiceTestvA SF (jiminny@localhost]4 HS_local [jiminny@localhost]Cascade# console [PKOb.# console leu)# console [slAGiNg)Hubspot Rate Limit Re+0 ..[2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"neaders".?pubize tunctzon getcontactayemazlistrang semall, array stzelas e li: array"Uace":L"Inu,or May 2020 14.21.15 6Ml"Jnuryt"Transter-Encod1nq":"chunked").Scontact = sth1s→>executeRequest(fn () = sthis-saetNeuInstance()->crm()>contacts(hasicAni()->getById($email, implode(',', $fields), null, false, 'email')"CF-Ray":L"9t80debödb60dcsa-S0F"J,"Strict-Transport-Security":["max-aqe=31536000: includeSubDomains: preload"].accent-encodino""access-control-allow-credentials": ["false"]."server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",return ['id' => Scontact->getId(), 'properties' => $contact->getProperties()]:} catch (RateLimitException Se) {throw Se.I let ioh middlevare handle} catch (ContactApiException Se) {// genuine 404 /chas→>log sintol Inuospot ratted to terch contact, l...areturn :"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"So+-Cookie"." c+hm-Stlirtd0aXVr.kSandas6hzVVKhzTn0BidvMaheCtm0V-1778163675-1.0.1Note executeRequest's current isHubspotRateLimit already includes ContactApiExcept ion so this works as-is — you just need to actually route the call throughit. Same pattern for getContactById, getOpportunityById, getAccountById, get0wners, batchRead0bjects, and the makeRequest() raw HTTP path.07-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Renont-To".r"*Why this matters with the rate-limiter increment in Matchcrmbata"endnoints".You moved this"unl".httns:a.nel.cloudflane.com./nenon+|W/v42c=NVA1cVTPQfVm32anS0ixVF/sd2RIMatchCrmData.nhn-112-112\"group)":\"cf-nel\","max_age\":604800}"]|"NEL":["{\"success_fraction\":0.01,"report to\":|"cf-nel\"."max age":604800}"]"Server": ["cloudflare"]}} {Scrmobiects = ScrmûhiectsResolver-sresolveFromcalsthis-scrmService. Sthis-scaldnSrateLimiter->incrementRequestCount(Sactivity->getCrm()):resolveFromCall may issue 2-4 HubSpot API calls (email + phone + domain + identifier matches). The job-level limiter still counts that as 1. Today this was OKbecause there was no client-side limit at all. Once the new reactive limit is in place:• If any inner call 429s, RateLimitException bubbles → middleware releases the job → incrementRequestCount is never called for that attempt"correlation_1d":"95256555-ec98-4541-b09za-adta/SboYeab".•The job-level counter stays low; the next attempt tires immediately when middleware delay expires"trace_10":C/AD8565-905t-4604-9405-0e5b551e5545• Net effect: the client-level reactive limit is doing the real backoff; the job-level limiter is now a much coarser secondary guard. This is fine, but means the ProviderRateLimiter quota numbers should probably be relaxed (or the increment moved closer to each underlving API call. e.a. inside executeRequest () itself).Strona suadestion.lf.vouwant theliob-levelimiter to.remain.meaninaftincrementlfromlinside/@llentz.execnteReauest7#lonce.ner.actuallkTTiD.callnot onceSummary# QuestiorRecommendationMap RateLimitException → HTTP 429 with Retry-After in CrmController: optionally one in-process retry of min(retrvAfter. 1) s inside findGuintinn alondReplace blind sleep(1) with sleep(min(Se->getRetryAfter(), 30)) keyed on RateLimitException - or better, let it bubble to Hand leHubspotRaMATphsyarWnantContoctRufantl ond tho othor dirort.COK mothode lootContoctßutd antonortunitulutd aotferountßutd botchboodbhdocte eabobonunct)middloworo inotfontivo for tho moct common noth Douto thom throuch ovocutoPonuoct() co thoy omit Potol initEvcontion Alen roconcidor whoroOk lets make it extremelv simple, Onlv consider÷ « CodeClaude Onus 4.7 MediumW Windsurf Toamo091-28 (61 charc 1 line hreakUTE.8Po 4 spaces...
|
PhpStorm
|
faVsco.js – Client.php
|
NULL
|
15282
|
|
15160
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
PhostormVIewINavicareCodeFV faVsco.js°9 JY-20725-handle-HS-search-rate-linroledey© BatchSyncCollectolyhuospotsyncstrategybase.ongT SyncCrmEntitiesTrait.phpCachedcrmservicebecorator.onp© ProspectCache.phpe balchsynckealsseo cllent.oneccloseaDealstagess @ MatchacuivitycrmData.ong© CrmActivityService.phpDealrielasservice.gc)Decorateacuivilv.or©FieldDefinitions.php 1455© Fieldlypeconvertel 145€U HubspotClientinterl 1457© HubspottokenMani 1458 Gt ›© PayloadBullder.php 147%© RemoteCrmObjecth 1478% ResponseNormalize 1479C) Service.ond1486© SyncFieldAction.ph 1481© SyncRelatedActivit) /e2 Gt ›© WebhookSyncBatcl s1zv MintearationAorclass servace extends Baseservace ampLements* dinheritdocmA7 A48 X1 X33 M1 A1514 б >M Acceccors•MAn1547 Cf>• D ConfigDDTO• M Silters1578 GD Jobs11575D ProspectSearchStre 1586W sevice lraits1581© DataClient.php© DecorateActivity.ph11583cLocalsearch.oneU Localsearchintertar 1589© RemoteSearch.phpc) Service.phpv W Listeners© ConvertLeadActivit 1580© PurgeLookupCache 159G> M Metadata1591> Miaration1592Pioedrivev Salesforce1594• D Fields1505 (> OpportunityMatche 15o/OpportunitySyncSticonM ProsneetSearchStr.M ServiceTraitcC) Client nhr© DecorateActivity.pt .. Delete@biectsTrait@ FieldDefinitions.php 1602 G© PayloadBuilder.php 1603© Profile.php© QueryBuilder.phppublic function getRecord(string $objectType, string $objectId, array $fields = []): array{...}* @throws BadRequestxoctrows crmExceptionpublic function updateStage($crm0bject, Stage $stage): void{...}public function generateProviderUrl(string SproviderId, string $obiectType): ?string{...}public function searchCalls(Carbon $from, Carbon Sto, string SactivityProvider): array{...}6 usagespublic function searchCallsForPeriodByPaqe(Carbon $from, Carbon $to, int Spage, bool Sretry = true)Spavload = sthis->navloadBuilder->qenerateSearchcallsBvPeriodPavloadSfrom. Sto. Soaqe):return $this->client->search( objectlype: 'calls', $payLoad):} catch (Exception Sexception) {Sthis->Logger->info('[HubSpot) Search calls for period failed', lnat: self::LOG_DATE_FORMAT),ito' => Sto->formatfoself:L0G DATE FORMAT).."reason' => Sexcention->aetMessadeOriif (Sretry) 1cleend seconds.1return $this->searchCallsForPeriodByPage($from, $to, $page, retry: false):return null:Zusagespublic function searchCallsForPeriod(Carbon Sfrom. Carbon Sto): GeneratonSthis->logger->info('[HubSpotl Search calls for period'. ""from' => Sfrom->formatll format: self::L0G DATE FORMATO)40Dally - Platrorm • In 22m100% L2• Mon 11 May 9:23:56AskJiminnyReportActivityServiceTest v+0 ..=1819=29I1 11.A SF (jiminny@localhost]4 HS_local (jiminny@localhost]# console [PKob.# console [euJ# console [slAGiNG)2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"Vace". "Inu,ur May 2020 14.21.19 6Ml"Jn"concenc-lyoe. apolicacion/ison.charser=utt-on"Transfer-Encoding": ["chunked"]."CF-Ray": ["9f80deb8db60dc3a-SOF"]."CF-Cache-Status": L"DYNAMIC"J,"Strict-Transport-Secur1ty":"max-aqe=31536000* 1ncludeSubDomains: preload")acceot-encodino"."access-control-allow-credentials": "false"i."server-timing": ["hcid;desc=|"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfr;desc=|"9f80deb8e7c6dc3a-1AD\""J,"x-content-tvoe-ootions":"nosniff"."x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"Set-Cookip"." c+hm=Stlirtd0aXVr.kSandas6hzVVKhzTn0BidvMaheCtm0V-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Report-To":["{"endnoints".("url\":"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RV("group\":\"cf-nel\".("max_age\":604800}"],"NEL":["{"success_fraction\":0.01,reportto. "cr-nel,"max agel ":604800}"].'Server": ["cloudflare"]}} {"correlation_1d":"95256555-ec98-4541-b9za-adta/Sboyeab","trace_10":"C/AD8565-905t-4604-9405-0e5b551e5545CascadeHubspot Rate Limit Ressues roundCritical1. find() swallows RateLimitException silently inside a Cache: : remember callback• Service.php:598-656$response = $this->client->search($objectType, $payload):} catch (BadRequest se) {throw Secllent→>search can now throw Ratel1m1texcept zon (which extends LoqicException, not BadRequest. The catch block only catches BadRequest . RateL1m1tEXcention will bubble out of the Cache:remember callback — which then caches the excention throw-path.with.the bad.result (Laravelis Cache:.remember doessearch used in the Ulextension) Will ger an unnandled exception. Tnis is Inconsistent with the intent - those callers don tnave nand lenuospockateL lmimiddleware2. searchCallsForPeriodByPage/ searchCallsForPeriod/searchCallByRecordingURLToken eat the RateLimitExceptionAll three catch Eycention• Service.php:1584} catch (Exception $exception) {RateLimitException extends LogicException which extends Exception ? Let me verify:Searched class LogicException in app/Exceptions/LogicException.php (2)RateLimitException extends LogicException extends \LogicException extends \Exception. So all catch (Exception se) blocks in Service. php will swallow theRateLimitException - rate limit events are silently treated as call-not-found and processing continues, losing the ability to back off. This includes:• searchCallsForPeriodByPage → calls sleep(1) and retries once with no back-off awareness•searchcallByRecordingURLToken → same pattern• The do-while loon in aetCal1s() (line 1561) — continues to neyt page as if the page returned emoty.Serious3. MatchActivityCrmData has HandleHubspotRateLimit middleware but the actual CRM call path may not throw RateLimitExceptionMatchActivityCrmData calls_crmAct/vityService=>updateCrmData.which eventually calls.match=xactiyBvEmall→ netContactBvEmai0. That method doesnot go through executeRequest( ) - it uses the SDK directly with no rate limit wrapping:b Client.php:503-523public function getContactByEnail(string Semail, array stields = (l): arraytryf$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(...)The middleware is attached.but the underlving.oath_doesnit propaaate RatelimitFxcention.for that method..it willonlv_fire.if somethina.alona.the wav.uses.executeReguest() / search(). The middleware is only partially effective4. getAsseLimitException and re-throws it - but the wrapped catch (\Exception se) that follows would still catch it before there-throw if the order were different. Order is currently correct, but the separate re-throw for RateLimitException is redundant boilerplate since the next catch isAsk anvthing (84D)+ « CodeC° AdantiveW Windsurf Teame1585-22UTF.8Po 4 spaces...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
15160
|
|
16158
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
PhostormVIewINavicareCodeLaravelKeractorTOOISFV faVsco.js?9 JY-20725-handle-HS-search-rate-limitroledey© OutOfBoundsException.pyhuospotsyncstrategybase.ongQuotaExceededExceptiorKateLimitexception.onp© RegistrationInvitationMisr)MatchactivitycrmData.pnpC Job.php© RequestQueuedForDeferrResponseException.php© RingCentralException.php©PaginationConfig.phpRingCentralExtensionNotlrohoRuntimeException.php( SequenceNumberExceptideclare(strict tvoes=1)):@ ServicelntegrationExcept( ServiceUnavailable Excep• SidekickSettinasExceptionamespace Jiminny Excentions:(4 Socia Account NotFoundeluse Throwahile:© SocialAccountTokeninvali(SvncActivitvExcention.ohclass RateLimitException extends RuntimeExceptionTenantisolationException. 10© TextRelayException.php© TooManyFailedActivities.1 12public function __construct(string smessage ="4 TranscrintionNotindeyedi 12private readonly int SretryAfter = 1,© UnexpectedCallException 14© UnexpectedEloquentMod 15© UnexpectedValueExcepti 18cInrowable sprevious = nuut.р{...3© ZipAttackException.phpD FFMpegpublic function getRetryAfter0: int{...}lD) Formats> D Guards> 0 Helpersv D Http• _ AccessI okenProviderv C Controllersv DAPI> D AiCallScorindAlReports• DeallnsiantsOoportunit• → Page• Scorecards• SettinasTeaminsiahts• M Themecv MUserAutomatedRer(C) UserAutomatediv DV2C) ActivitvV2Contr8) AckAnvthinaGor(C) Ack liminnvRend( NonleV2Controll(e OnNemandv2e,0 DievlictControlle"a) DiaulictCharoCnlelner Code will hoin INF to underctand vour Laravel ann code II Generate II Don't Show Anvmore (todav Q•08)© ProspectCache.php=custom.logx=laravel.logA SF (jiminny@localhost]4 HS_local (jiminny@localhost]# console [PKob.# console [euJ# console [slAGiNg)2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {neaders.?Vace". "Inu,ur May 2020 14.21.19 6Ml"Jn"Loncent-lvoe". "apolicacionison charser=utt-o"Transfer-Encoding": ["chunked"],"Connection":"keep-alive"."CF-Ray":"9t80deb8dbo0dcsa-S0F"n"CF-Cache-Status": L"DYNAMIC"J,"Strict-Transport-Secur1ty":"max-aqe=31536000* 1ncLudeSubDomains: preload")nacceot-encodino""access-control-allow-credentials":["false"]."server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfr;desc=|"9f80deb8e7c6dc3a-IAD\""],"x-content-tvoe-ootions":"nosniff"."x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"Set-Cookie"." c+hm-Stlirtd0aXVr.kSandas6hzVVKhzTn0BidvMaheCtmoV-1778163675-[IP_ADDRESS]-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"])"Renont-To". "s"endnoints".'"url"."httns:a.nel.cloudflane.com./nenon+/v42c=NVA1cVTPQfVm32anS0axVF/sd2Rl"group\":\"cf-nel\","max_age\":604800}"],"NEL":["{"success_fraction\":0.01,25report to. "cr-nel,"max age ":604800}"].'Server":["cloudflare"]}} {"correlation_1d":"95256555-ec98-4541-b9za-adta/Sboyeab"'trace_10":"C/AD8565-905t-4604-9405-0e5b551e5545Support Daily - in 3h 44 m100% C. • Mon 11 May 11:16:16AskJiminnyReportActivityServiceTest v :CascadeHubspot Rate Limit Re+0 ..daily limit - escalating SECONDLY → TEN_SECONDLY_ROLLING → DAILY_LIMIT. After DAILY_LIMIT triggers, ALL HubSpot operations on the portal (other jobs,the Chrome extension, manual Ul clicks stop working until midnight UTe3. Log/Sentry pipeline saturation. ~900k log entries in 30 min = 500/sec sustained. Each MatchActivityCrmData: :handle error includes a full stack trace (550KB). That's 2.5-25 MB/sec to your loa pipeline. Sentry will rate-limit you. Datadog/cloudWatch will throttle ingestion. Your bill spikes4. Queue worker starvation. All 50 analytics_low workers are busy in the rate-limit loop. Every other job on QUEUE_ANALYTICS_LOW (other CRM jobs, reportingetc. sits in queue waiting, Enective throughput on that queue for non-Hubspot work: 0.Hiah5. Database churn. ~245 transactions/sec x 1800s = ~441k transactions opened and rolled back. Each one includes UPDATE activities + UPDATE participants forthat row. Innodb undo loas grow, page cache thrashes. Replica laa possible6. Redis memory growth. Released jobs sit in Redis ZSETs. With 245 releases/sec at ~5KB each (job payload), that's 1.2 MB/sec growth in delayed queue.Returns after 1s. so steady-state size is bounded — but durina the storm Redis memory is several hundred MB elevated7. The MAX RATE LIMIT ATTEMPTS = 20 cap is harmful, not protective. As traced above, jobs that hit it enter a slow 30s/90s/180s backoff loop while the cachelents. This actually extends the time a iob lives in the svstem. holdina the unique lock longer. With uniqueFor = 31min set. this is still bounded.altintn slolacloh© Medium8Successfulliohs stillisnenditimelin.retries.offthe 91000/successfmlliobsthe.averade.one.was.nrobablvretried100.timeslbefore.succeedina/lofitery.oddstinthe 5/sec window). Their unique locks were held for 30+ minutes each9. failed() callback doesn't tell anyone. No alert, no dashboard, no email. 91k silent failuresWhat Would Actually HelpIn order of impact:1. Proactive cache circuit-breaker (you already discussed this). When ANY worker sees 429, set Cache:: put ("hubspot: ratelimit:{SportalId}", SretryAfter, $retrvAfiter Other workers fast-failno APl call until cache exoires. Reduces the 250 oos/sec to ~1 oos/sec durina a storm — every worker iust sleens. Wit50 workers all releasing on stale cache, throughput becomes ~5/sec actual + 0 wasted2 Provider-levelthrouahout can.before disoatch.Instead of disnatchina.all 100k.at.once.throttle.the disoatcher.so_the aueue.holds.a.max.of.Nliobs.at.anv. timepredicate, outracchaccivitycrbata doesh tuse lu3. Longer retryUntil or different strategy. With 100k jobs through a 5 RPS bottleneck, the math says you need 5+ hours minimum. 30 min is a guarantee that91% will fail. Either• Rumn retrvuntil to 6+ hours (but locks held that lond is its own nroblem)•Don't use lobs tor this - use a single batch processor that paces calls4. Drop MAX RATE LIMIT ATTEMPTS cap as l mentioned, It's net negative — extends iob lifecvcle without preventina eventual failure (retrvUntil already does thatcleanly).5. Skio stack-trace loa on RateLimitExcention, ~50% loa volume reduction durina a storm.Worker-count SensitivitvDoesn't change the conclusion. The bottleneck is HubSpot's 5 RPS, not your workers. More workers just mean:• Higher wasted-APl ratio (more 429s)• Same successful throughput (5/sec)• Sacter time to hit DAll Y LIMIT eccalation• More log volume10 workers: same 9.000 successes in 30 min. fewer wasted calls (50/sec vs 245/sec). 100 workers: same 9.000 successes, more wasted calls (~495/sec)Ask anvthina (&4L)+ « CodeClaude Onus 4.7 MediumwW Windsurf Toamoio 4 spaces...
|
PhpStorm
|
faVsco.js – RateLimitException.php
|
NULL
|
16158
|
|
16405
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
PhostormVIewINavicarecodeFV faVsco.js°9 JY-20725-handle-HS-search-rate-limroledey© HubspotWebhoc© HubspotSyncStrategyBase.phpv @ PaginationC Paginationcontic* RateLimitexC) Paginationstate•_ Prospectsearchstr> 0 RedisC) ProviderRateLimiter.phpC) PaqinationConfia.phpv D ServiceTraitsclass HubsootPaginationServicem A12 ^ v# Opportunitysync+ SyncermEntitiesT SuncFieldstrait.T Writecrmtrait.p•DUts• WeonookC) BatchSvncCollectoC) BatchSvncRedisSe© Client.phpC) ClosedDealStadessG DealFieldsService.p© DecorateActivity.ph© FieldDefinitions.phpC) SieldTvneConverte(0) HubsnotClientinter© HubspotTokenManUPayloadsunlder.pnp 101G DomatoermAhiontiUa) DocnoncoNlormalizec) service.ono© SyncFieldAction.ph© SyncRelatedActivity 106c) WebhooksyncBatcC IntegrationApp› Accessors• W Api|• contioMDTO• FiltersaobsServiceTraitsC) Dataclient.ohoC) DecorateActivitv.ofC LocalSearch.nhn(0 Loca|Searchinterfad© RemoteSearch.php© Service.phpv D Listeners© ConvertLeadActivite Duraol aokunGachalM Motadata• M Miarationpublic function getpaginatedbataGenerator'total_records_fetched' => Sstate->totalRecords,Itotall elansed seconds: => roundisstate->aetslansedSecondso. orecision: 7).'average_seconds_per_request' => $state-›requestCount › 0 ? round( num: $state->getElapsedSeconds(// Update reference parametersStotal = $state->total;$lastRecordId = $state->lastRecordId;private function shouldStopPagination(PaqinationState $state, int SteamId): boolf...}private function handlePaginationStrategy(array Spayloadarrav soetaultrzlter.PaginationState $state,arrav "...;private function shouldSwitchToKeysetPagination(PaginationState $state, int SresultsPerPage): boolt...,private function validateTokenIfNeeded(Client Sclient, PaginationState $state): voidt...}lusageprivate function executeSearchRequest(Client Sclient, string SobjectType, array Spayload, PaginationStatetryfreturn $client->search(SobjectType, Spayload);} catch (\Exception $e) {i4 (6cljont-sicllnauthonigedFycention(6o))SSthis->logger->warning('[Hubspot] Got 401 during pagination, attempting token refresh'. ['team id' => Sclient-›qetConfiq(->qetTeam@->qetIdo'error' => $e->qetMessage(1:Scuient->ensureValidTokenosolner Code will hoin INF to underctand vour Laravel ann code II Generate II Don't Show Anvmore (todav Q•08)25A SF (jiminny@localhost]4 HS_local (jiminny@localhost]# console leu)# console [slAGiNg)2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"Vace". "Inu,ur May 2020 14.21.19 6Ml"Jn"Concent-lvoe". "apolicacionison charser=utt-on"Transfer-Encoding": ["chunked"]."CF-Ray":"9t80deb8dbo0dcsa-S0F"J,"Strict-Transport-Secur1ty":"max-aqe=31536000* 1ncludeSUbDomains: preload"),"access-control-allow-credentials": "false"."server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfr;desc=|"9f80deb8e7c6dc3a-IAD\""],"x-content-tvoe-ootions":"nosniff"."x-hubsoot-correlation-id":"019e02d0-6fd8-7812-bdba-885b7ccb3ee3"7"Set-Cookip"." c+hm-Stlirtd0aXVr.kSandas6hzVVKhzTn0BidvMaheCtm0V-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Renont-To".f"s"endnoints".("url\":"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RV("group\":\"cf-nel\".("max_age\":604800}"],"NEL"L"1"success_fraction\":0.01,reportto. "cr-nel,"max agel ":604800}"].'Server": ["cloudflare"]}} {"correlation_1d":"95256555-ec98-4541-b9za-adta/Sboyeab","trace_10":"C/AD8565-905t-4604-9405-0e5b551e5545• suppont Dally • In 3h 11m100% 2• Mon 11 May 11:49:04AskJiminnyReportActivityServiceTest -CascadeHubspot Rate Limit Re+0 ..ReasonRateLimitException.phpRemoved policy field & methodsMiddleware doesn't need it: cache TTL handles DAILY naturallycache stores scalar int retry after) instead of arraySimpler: no policy to trackDrop policy from RateL1m1tException constructorMatch new exception signature; still log policy for observabilityRemoved DAILY LIMIT branchretryUntil + long cache TTL handle it; saves complexityMIN RETRY DELAY 5 →1Named JITTER SECONDS constantSelf-documentingCollapsed dual catch into single catch + instanceofMore readable; no awkward empty rethrow blockHow DAILY LIMIT now flows (no special case needed)1. HubSpot returns 429 with policyName: DAILY_LIMIT2. parseRetryAtter sees no Retry-After header, falls through to policy table → returns 600s (the DAILY_LIMIT detault lleft in parseRetryAfter)3. Cache populated with TTL=600 (10 min)4. All subsequent requests fast-fail via cache for 10 min - no API calls5. Middleware releases iohs with delav 1-6c (chean evcles. all hit cache)6. After 30 min, retryUntil expires → jobs permanent-fail naturally7. No special branch. no siob→>failo, no excention fieldThe system converges to the same outcome with less code.Re-running the 100k scenario (delta from previous run)Material changes vs the previous version:•Job retry cvcle is faster (delav 1-6s instead of 5-10s) → ~2x more queue cvcles per second per worken• More cache hits per second (since cycles are faster) - but cache GETs are cheap (~0.1ms)• Same throughout ceilina (5 successtul calls/s — HubSoot's limit))• Same final outcome (29k succeed. 291k fail at T-30min)|MetricPrevious (this round)This roundSuccessful jobs in 30min9,0009,000Wasted HubSpot API calls~10,800~10,800Job pop cycles/sec~50-100~100-250|Log entries (with sampling)~10000~10.000Averade delav ner releace275gThe faster retry cycle gives you slightly better responsiveness when the cache window expires (more "lottery tickets" at HubSpot's open second), but doesn'tThe fundamental remaining issue is unchanged: 30 min x 5 RPS = 9k jobs ceiling. To process all 100k, you either need ~6 hours window, or batch-endpointredecian. or disnatch-side throttlingG al ... (2 files with chanaesann/lohe/Crm/M MatchActivitvCrmData.nhn 412-8View allann/lobs/Middleware/M HandleHubsnotRatelimit.nhn +12-20ot/m Client.oholReiect allAccent allAsk anvthina (&4L)+ « CodeClaude Onus 4.7 MediumWN Windsurf Toams 26.52 UTF.Rio 4 spaces...
|
PhpStorm
|
faVsco.js – RateLimitException.php
|
NULL
|
16405
|
|
16533
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
SlackFileEditViewGoHistoryWindowHelpDOCKERO 81DEV (docker)882DEV (d)APP (-zsh)• xзmasterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY] laysJY-20698-fix-SF-activity-types-on-new-playbookJY-20543-AJ-report-trackingJY-20384-handle-auto-sync-with-no-access-to-event-typeJY-20458-ask-Jiminny-user-definitionsJY-19666-fix-import-contacts-account-associationJY-19666-HS-import-contacts-and-accounts-batch-jobJY-20458-Ask-Jiminny-ReportsJY-20200-batch-update-CRM-objects-SalesforceJY-19666-HS-webhooks-add-contact-and-companyJY-20348-trigger-setup-DI-layout-on-team-creationJY-20326-refactor-info-message-in-commandJY-20317-fix-auto-log-delay-issue-on-all-channels-disabledJY-20312-remove-on-update-change-last-synced-at-crm-configurationsJY-20306-SF-skip-auto-sync-for-task-based-playbookJY-20192-remove-deleted-team-from-saved-search-filtersJY-20197-import-opportunity-batch-jobJY-20293-enable-status-field-for-pipedrive-dealsJY-20191-remove-commands-interactive-promptsJY-20118-change-default-sync-strategyJY-20183-add-cache-on-auto-log-delayJY-20197-add-import-opportunity-batch-job20118-hs-opportunity-make-webhook-strategy-defaultJY-20118-make-default-hs-opportunity-sync-strategy-webhook-basedJY-20196-handle-opportunity-without-noteJY-20118-improve-opportunity-importJY-20189-handle-activity-search-on-deleted-groupsJY-20145-filter-out-converted-leads-when-matchingJY-20150-skip-push-summary-on-summary-ready-1f-autologJY-20132-fix-note-encodingJY-19792-clean-logslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-Lirroot@docker_lamp_1:/home/jiminny# ]HomeDMsActivityFilesLater..•More• Support Daily - in 2h 58 m100% C8• Mon 11 May 12:02:41ED→Describe what you are looking forJiminny ...crsmecruus# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...0 Direct messagesa. Stefka Stoyanova€. Vasil Vasilevo Nikolay Ivanov. Galya DimitrovaAneliya Angelova, .... Stoyan TanevVes®. Aneliya Angelova& James GrahamE Lukas Kovalik y…..:: AppsJira CloudLToastGoogle Cale...Stefka Stoyanova• Messages7 Untitled+C Files7 Untitledluesaay, April 28th ~Today ~Stefka Stoyanova 10:08 AMЛукаш, щом пре-рефайнмънта и рефайнмънтаще са само за МСР ако искаш не идвай да сигубиш времетоLukas Kovalik 10:12 AMда, няма да идвамStefka Stoyanova 11:35 AMЛукаш, ще сложиш ли естимейт наhttps://jiminny.atlassian.net/browse/JY-20818Jira Cloud -Move Ask Jiminny reports to separate...Bug JY-20818 in Jira CloudStatusDeployedPriority= MediumAssigneeLukas Koval...As of today at 11:35 AMOpen in Jira* SummariseMessage Stefka Stoyanova......
|
PhpStorm
|
faVsco.js – HandleHubspotRateLimit.php
|
NULL
|
16533
|
|
15280
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
iTerm2ShellEditViewSessionScriptsProfilesWindowHelp(ah)Daily - Platform - in 5 mA100% C47 8• Mon 11 May 9:40:22DEV (docker)• жз181DOCKER-₴81DEV (docker)882APP (-zsh)|masterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY] laysJY-20698-fix-SF-activity-types-on-new-playbookJY-20543-AJ-report-trackingJY-20384-handle-auto-sync-with-no-access-to-event-typeJY-20458-ask-Jiminny-user-definitionsJY-19666-fix-import-contacts-account-associationJY-19666-HS-import-contacts-and-accounts-batch-jobJY-20458-Ask-Jiminny-ReportsJY-20200-batch-update-CRM-objects-SalesforceJY-19666-HS-webhooks-add-contact-and-companyJY-20348-trigger-setup-DI-layout-on-team-creationJY-20326-refactor-info-message-in-commandJY-20317-fix-auto-log-delay-issue-on-all-channels-disabledJY-20312-remove-on-update-change-last-synced-at-crm-configurationsJY-20306-SF-skip-auto-sync-for-task-based-playbookJY-20192-remove-deleted-team-from-saved-search-filtersJY-20197-import-opportunity-batch-jobJY-20293-enable-status-field-for-pipedrive-dealsJY-20191-remove-commands-interactive-promptsJY-20118-change-default-sync-strategyJY-20183-add-cache-on-auto-log-delayJY-20197-add-import-opportunity-batch-job20118-hs-opportunity-make-webhook-strategy-defaultJY-20118-make-default-hs-opportunity-sync-strategy-webhook-basedJY-20196-handle-opportunity-without-noteJY-20118-improve-opportunity-importJY-20189-handle-activity-search-on-deleted-groupsJY-20160JY-20145-filter-out-converted-leads-when-matchingJY-20150-skip-push-summary-on-summary-ready-1f-autologJY-20132-fix-note-encodingJY-19792-clean-logslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ devroot@docker_lamp_1:/home/jiminny# ]-zsh-zsh885screenpipe"0 ₴6DEV...
|
PhpStorm
|
faVsco.js – Client.php
|
NULL
|
15280
|
|
15084
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
PhostormINavicareCodeFV faVsco.js°9 JY-20725-handle-HS-search-rate-limroledey© SyncRelatedActivityManager.php(c) PemoteCrm@biectl® ResponseNormalize© HubspotSyncStrategyBase.phpCachedcrmservicebecorator.onp© ProspectCache.phpg service.onpg) syncrielaAction.on© MatchactivityermData.png© CrmActivityService.phpC) synckelatedAcuivilc) wednooksynebalcv @ IntegrationAppclass Service extends Baseservice 1mplementsM |A7 A48 X1X33 21 A V 15* dreturn nulularrous› D Accessors• W Api|896LeadinuleAccountlnulz.• contioO DTO• D FiltersOpportunitylnull,Contactlnul.HoosProsoectSearchstrStage/null,strinalnulService TraitsC) DataClient. ohoO040public function matchByDomain(string $domain, ?int $userId = null): ?arrayC) DecorateActivitv.ohC) LocalSearch.ohv$companyName = $domain;ilocalSearchintertat907© RemoteSearch.phpC) Service.phpv D Listeners© ConvertLeadActivitC) Purael ookunCache/I Try to find a company matching their email domain.ScompanyProperties = [country'phone'III 1I4> D Metadata>D Migration> @ Pipedrive"name"'hs avatar filemanager_key'"industry',Console,Log XChanaes 12 filed= env.local aonC) Client.oho aon/Services/Crm/Hubsooti+ → Side-by-side viewer •Do not ignoreHighlight wordsx 13 B?8 35f036ac app/Services/Crm/Hubspot/Client.phgSdeal = Sthis->qetNewInstance()->crm()->deals()->basicAni@->getBvId(© HandleHubspotRateLimit.php app/Jobs/Middleware© HubspotClientinterface.php app/Services/Crm/Hubspot© HubspotPaginationService.php app/Services/Crm/Hubspot/Pagination@ JiminnyDebugCommand.php app/Console/Commandsphp logging.php config© MatchActivityCrmData.php app/Jobs/Crm© MatchCrmData.php app/Jobs/Activity/Import© PaginationState.php app/Services/Crm/Hubspot/Pagination© RateLimitException.php app/Exceptions© Service.php app/Services/Crm/HubspotUnversioned Files 9 filesimolode('.",. Sfields).Sendpoint = self::BASE_URL • $endpoint;if Smethod === IGET!) 4neturn Sthis->aetTnstance@->aetcljient02->requestdmethod: $method,endnoint• Sendnoint.= env.nikilocal apo=.env.other app© CanAccessAiReportsTest.php tests/Unit/Policies• CreateMockAskJiminnvReportResultCommand.php app/Console/Commands/Repquery_string: $queryString3olco Sireturn Sthis->getInstance(->getClient->request($method, $endpoint, [ki tavicon.ico public'ison' => ($payload).E ids txt apriaraw sol querv sall aool@ SimulateWebhooksCommand.ohnapp/Console/Commands/Crm/Hubspotolner Code will hoin INF to underctand vour Laravel ann code II Generate II Don't Show Anvmore (7 minutes aaol$0hellDally - Platrorm • In 30m100% Lz. Mon 11 May 9:15:35AskJiminnyReportActivityServiceTest v=custom.log ^=laravel.logA SF (jiminny@localhost]4 HS_local (jiminny@localhost]Cascade# console [PKOb.A console [EU]A console [STAGING]0 HubSpot Paginationaccept-encoding"],"access-control-allow-credentials":["false"]."server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfr;desc=|"9f80deb8e7c6dc3a-IAD\""],"x-content-type-options": ["nosniff"],"x-hubspot-correlation-id":("019e02d0-6fd8-7812-bdba-885b7ccb3ee3"].Read Hub:Now let me read the HubSpot Client.php and Service.php, focusing on the rate limit and search-related methods:6 Fast Context RateLimod rate limit handlina in HubSoot Client.oho in 2.716Let me read the full Client.php and the HandleHubspotRateLimit middleware, plus the ProviderRateLimiter:"ser-Lookle:ct.Dn=sLurcaugxvrzksopacronzvyknzinubzovrabectmoy-1//81050/5-1.0.207-May-26 14:51:15 GMT: domain=.hubapi.com: Http0nly: Secure: SameSite=None"],Read Client.phpNow let me read the HandleHubspotRateLimit middleware and ProviderRateLimiter"керогс-10":"1Explored 2 files and searched 2 queriesenapolnus"."url":nccos:a.nel.cloudtlare.comredorcV4.S=NYALSVIPorymszorSUnxY24S0ZKhNow let me look at the HubSpot Service.php for how search is used, and the CrmObjectsResolver"max_age\":6048005"J,"NEL": ["{"success fraction":0.01.Now let me look at the git diff to understand what's changed:Command git"max ade".604800-""Serven"•["cloudflare"]}} {-C /Users/lukas/j iminny/appt"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab" ,"trace id":"c7ab8365-903f-46d4-9403-0e5b551e3545"Ask anything (&AL)+ ‹> CodeSAdaptiveSdeal = Sthis->getNewInstance()->crm()->deals(->basicAni@->qetBvId(Scrmld,imolode('.". Sfields)$endpoint = self::BASE_URL . $endpoint;ifSmethod ==="GET!)Se = Sthis->aetInstance@->aetclient02->request(method• Smethod.query_string: $queryString3olco dnse = Sthis->getInstance(->qetClient->request($method, Sendpoint, ['ison' => ($payload).+0 ..• 014 differencesWN Windsurf Teams010-22io 4 spaces...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
15084
|
|
16247
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
PhostormVIewINavicareCodeFV faVsco.js°9 JY-20725-handle-HS-search-rate-lProiect© SyncRelatedActivityManager.phpD MeetingBo1• MiddlewareC HubspotSyncStrategyBase.pngy syneermenttes tralt.onp© ProspectCache.php© kateLimitea.ongD StreamingC) MatchActivitvCrmData.phg© Job.php*RateLimitexception.protkateLimitphp x© Client.phpa leamD Telephony(C)PaqinationContia.phgv D Userclass HandLeHubspotRateLimitc) ChangeEmailjob.phpDeactivateUserJob.ph(C) SetuoDetaultSavedSe:@ SvncTolntercom.php© SynctoPlanhat.php(C) SvncToUserPilot.ohoC BaseProcessina.lob.ohoC)Dummv.lob.oho© ImportRecallAlRecordings(c)ImnortRemoteTrack.loh.ncloh nhnC.lobDispatcher.onp@ JobDispatcherInterface.p 23© PurgeSoftDeletedOpporti• SqsVisibilityControl.phpv D Listenersv D ActivitiesMActivityProviderM.luctealiv D UserPilotc) TrackProviderin>[ Audio>C Botsv @ CoachingIntercomv M PlanhatC) CreateActivitvlc(C) CreateCoachina(C) CreateCoachina(C) CreateCoachind(C) CreateCoaching(C) Createcomment(C) CreateManaderi(C) CreateSelfCoact 37(C) CreateSharedEv 38> MUserPilot(C) Create AvailabilitvN© CreateCoachingFeee CrontoCommontNa© CreateLiveCoachN,(e) CrontoMontionNotinrivate const int MAX RETRY DELAY = 600.Accept Rejectorivate constiint MAX RATE LIMIT ATTEMPTS = 20private const int MIN RETRY_ DELAY = 5:pubLic tunction nandle(odgect >JoD, caLlable snext): voldtry €Snext(S100):} catch (RateLimitException $e) {if (Siob->attempts@ >=self::MAX RATE LIMIT ATTEMPTS)Loq: :error('[HandleHubspotRateLimit] Rate limit attempt limit reached, giving up'. [if (Se->isDailyLimitO) {'[HandleHubspotRateLimit] Daily limit exhausted, failing job permanently', [I'job_class' => Sjob::class'attempts' => Sjob->attemptsOl"rate Limit messade'$e->getMessage(),'policy' => $e->qetPolicyO1) :throw $e;Sioh->farl(se):return:Sretrvafter = se-›oetRetrvafterorSdelay = max(self::MIN RETRY DELAY, min(SretrvAfter, self::MAX RETRY DELAY))Sdelay = max( valueself::MIN_RETRY_DELAY. min(Se->getRetryAfteroSdelay += random_int(0. 5):...values: self::MAX RETRY_DELAY)):Log: :info('[HandleHubspotRateLimit) Rate limit caught, releasing job with delay', [lánh clacct es Sinhe.clace+ 3 of 4 files →=custom.log~=laravel.logA SF (jiminny@localhost]4 HS_local (jiminny@localhost]# console [PKob.# console leu)# console [slAGiNg).2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {headers'1"Vace". "Inu,ur May 2020 14.21.19 6Ml"Jn"Concent-lvoe". "apolicacionison charser=utt-on"Transfer-Encoding": ["chunked"]."CF-Ray": ["9f80deb8db60dc3a-SOF"]."CF-Cache-Status": L"DYNAMIC"J,"Strict-Transport-Secur1ty":"max-aqe=31536000* 1ncludeSubDomains: preload")acceot-encodino"."access-control-allow-credentials": "false"i."server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfr;desc=|"9f80deb8e7c6dc3a-IAD\""],"x-content-type-options": ["nosniff"],"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"Set-Cookip"." c+hm=Stlirtd0aXVr.kSandas6hzVVKhzTn0BidvMaheCtm0V-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Report-To":["{"endpoints ".rs("url\":"https:\V/\\/a.nel.cloudflare.com\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RV("group\":\"cf-nel\".("max_age\":604800}"],"NEL":["{"success_fraction\":0.01,"reportco. "cr-nel"max agel ":604800}"].'Server":["cloudflare"]}} {'correlation_ id":"95236535-ec98-4541-b92a-adfa73b69eab"."trace_10":"C/AD8565-905t-4604-9405-0e5b551e554540"suppont Dally • In 3n z5 m100% 47. • Mon 11 May 11:31:13AskJiminnyReportActivityServiceTestvCascadeHubspot Rate Limit Re+0 ..1. Check cache::qetnubspot:ratel1m1t:portal:42')• null on first callrcache chpty2. Make HubSpot API call (~150ms)3. First 5 succeed (within 5 RPS)4. Calls 6-50 - 429 with retry_after=15. First 429 hits,w- parsePolicy → 'SECONDLY'- cache::outhubsoot:ratemit:oortal:42retrv atter:lr poucy: SEcoNdly trels- throws RateLimitExcention6. Middleware catches- delay = max(5, min(1, 600)) + jitter(0..5) = 5..10s- 100 only on attemots 12.3 • 3 100 entries the rest oass attemots<=s)- Sioh->release(5..10)Critical change: as soon as the first worker writes to cache (around T=200ms into the second), all 49 other workers checking the cache fast-fail without an APICache::get - returns arraythrow new RateLimitException('cached'. 1, 'SECONDLY') ~ no HTTP callMiddleware catches. releases for 5-10cBy T=~1s:• 5 jobs succeeded with real API calls• ~5Jobs made real APl calls and got 429 (the ones that raced berore cache was populated• ~990÷ iobs hit cache and fast-failed each cvcle now ~10ms instead of ~200ms — 20x taster pop loop!)Wait - faster loop means more pops per second per worker. Let me recalculate.Steady State (T = 1s onwardEach worker now does.pop (5ms) check cache (1ms hit) throw - middleware release(5-10s + jitter) (1ms) - loop~10ms per cycle = 100 cycles/sec/worker x 50 workers = 5000 ops/sec.Buta evervob released waits 5-110 seconds before beind availab le again Ibecause oflititer on MIN RETRY DELAY -5 So releasediiobs accumulatein the delavedqueue and don't return immediatelyAfter cache TTL expires (1s for SECONDLY). one worker dets throuah1. Cache::get returns null2. Real API call → succeeds (HubSpot allows 1 in this 1s window if other portal traffic hasn't burned the quota)3. OR fails → cache repopulated for another 1sEffectively the system self-paces to ~1-5 successful calls per second across the whole worker fleet, matching HubSpot's actual capacity. No thundering herd.Per-second steady-state. system-wide4 files +91-33Accent alliAsk anvthing (84D)Claude Onus 4.7 MediumWN Windsurf Teamo24-27 UTE.Rio 4 spaces...
|
PhpStorm
|
faVsco.js – HandleHubspotRateLimit.php
|
NULL
|
16247
|
|
15118
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
PhostormVIewINavicareCodeKeractorFV faVsco.js?9 JY-20725-handle-HS-search-rate-limitroledey© SyncRelatedActivityManager.php© BatchSyncCollectol© HubspotSyncStrategyBase.phpCachedcrmservicebecorator.onp© ProspectCache.phpe balchsynckealsseo closedDealstagess)MatchactivitycrmData.ong© CrmActivityService.phpDealrielasservice.gc)Decorateacuivilv.or© FieldDefinitions.phr- A2 A64 X1X1 A VC) FieldT vpeconvertee Hubspotclientinterc) HubspotlokenmanC) PavloadBuilder.php* ochrows BadrequestC) RemotecrmobiectrP ResponseNormalizec) Service.ono* ochrows HubspotExceptzonRuatste funeten fakeferust(todhes Sandetat, frcthed CST , Sasyled ., atdtns Sauenstrdlos mAUC)SvncFieldAction.on=24C) SvncRelatedActivitSendpoint = self::BASE_URL • Sendpoint;C) WebhookSvncBatclv MintearationAorifSmethod =a= "GET'),M AcceccorsSresnonse = Sthis-›aetinstanceo->aetclientor->requestd•MAnmethod: Smethod.• D ConfigDDTO• M Silters737endpoint: $endpoint,query_string: $queryString131D JobsProcnectSoarchStra} else {740Sresponse = $this->getInstance->getClient->request($method, $endpoint, [W service lralts'json' => ($payload)© DataClient.phpConsole,Chanaes 12 filed= env.local aonTJ0 + → Side-by-side viewer •8 35f036ac app/Services/Crm/Hubspot/Client.phgDo not ignoreHighlight wordsx 13 B?C) Client.oho aon/Services/Crm/Hubsooti© HandleHubspotRateLimit.php app/Jobs/Middleware© HubspotClientinterface.php app/Services/Crm/Hubspot© HubspotPaginationService.php app/Services/Crm/Hubspot/Pagination@ JiminnyDebugCommand.php app/Console/Commandsphp logging.php config© MatchActivityCrmData.php app/Jobs/Crm© MatchCrmData.php app/Jobs/Activity/Import© PaginationState.php app/Services/Crm/Hubspot/Pagination© RateLimitException.php app/Exceptions© Service.php app/Services/Crm/HubspotUnversioned Files 9 filesI/ Fallback toSmessace = strtolower(se->cetressadeon:return str contains(Smessage.I'401 unauthorized') 1ll'http 401') |1str contains($message. 'status code 401') 11(orea match('/\b401\b/' Smessage) &s str contains(Smessaae. 'unauthorized')):= env.nikilocal apoE.env.other app©) CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/Repki tavicon.ico publicE ids txt apr* Validates and refreshes the access token if needed before API requests.} StoAssociations)•3entch (Eycontion Co) diaraw sol querv sall aool@ SimulateWebhooksCommand.ohn apn/Console/Commands/Crm/Hubspotthic-sloa-sennon/ifHubenotl Sailod to Gotch accociationetПolner Code will hoin INF to underctand vour Laravel ann code II Generate II Don't Show Anvmore (10 minutes aao)=laravel.logA SF (jiminny@localhost]4 HS_local [jiminny@localhost]# console [PKOb.A console [EU]A console [STAGING]accept-encoding"],"access-control-allow-credentials":["false"],"server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfr;desc=|"9f80deb8e7c6dc3a-IAD\""],"x-content-type-options": ["nosniff"],"x-nuDspor-correlac1on-1d:l "0ryeuzdu-or0o-/812-baba-oosl/ccbsees"Set-Cookie":["_cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.107-May-26 14:51:15 GMT: domain=.hubapi.com;: Http0nly: Secure: SameSite=None"]."керогс-10":"1enapolnus"."url":nccos:a.nel.cloudtlare.comredorcV4.S=NYALSVIPorymszorSUnxY24S0ZKhN"group\":1"cf-nel\","max_age\":6048005"J,"NEL": ["{"success fraction":0.01."max ade".604800-""Server"."cloudflare"l?,"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab","trace id":"c7ab8365-903f-46d4-9403-0e5b551e3545";Curront vorcionDally - Platorm• In 2/n100% S2• Mon 11 May 9:18:13AskJiminnyReportActivityServiceTest vCascade• HubSpot Pagination+0 ..oull request #12057 from jiminny/JY-20819-increase-download-transctip-rate-limit75 -20817-T1x-deleting-old-tracksbeeat38938 MX-20 17 Frx delet 122 07 Frackiminny/2Y-20662-remave-Mord-honshead users/Lukas/jmhmy/app Log -oneLine -all -- app/services/crm/iubspot/Paghha &.on/iubspo tPaglnatLonService. php 223175f56eac13a JY-19456 fax param va suagestl6de4385261 JY-19401 extract HS pagination logic to separated classesCommand git, grep, head• git -C /Users/lukas/jiminny/app branch -all | grep -i "rate)|match\|pagination\/crm" | head -20 2>&1Run *w SkipAsk anything (&AL)+ <> CodeSAdaptive• 014 differencesreturn se-›getresponseo?->qetstatuscode === 4017Smessage = strtolower(Se->qetMessage))return str contains(Smessage.'401 unauthorized') 11str contains(Smessage.'htto 401') 11str contains(Smessage."status code 401)(orea match('/\b401\b/'. Smessage) === 1 as str contains(Smessage. 'unauthorized'))•* Val idates and refreches the access token i* needed heforp APT reauests.StoAssociations).} catch (RateLimitException $e) {thnow So.WN Windsurf TeamcPo 4 spaces...
|
PhpStorm
|
faVsco.js – Client.php
|
NULL
|
15118
|
|
16913
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
PhostormcodeFV faVsco.jsroledeyg createnotes.ong© SyncRelatedActivityManager.phpС MаLсhACuViLies lONeWс маchаcиvilycrmbatae Noteoblect.onpС CпескAnакetrукemotematch.png~/Iminnyapo/apo/Joos/crm/Delere/Delerecrmenutytrai.ono© saveAcuivity.ongcsavelranscriouion.onc© SetupLayout.phpC) Client.phpphpidehelper.php©) PaqinationState.phoC) MatchCrmData.phpC) CrmObiectsResolver.phoc) SyncActivitv.phpC) ProviderRateLimiter.php©) PaqinationConfia.php© SyncFieldMetadata.phc) SvncHubspotObiects.rmay Sycentions)X P Cc W .*4I7:© SyncLeads.phpclass Macchacuivicvurmbara excenos Job 1mplemencs snoulouueue, shoulabeunlquec) SvncObiects.ohp© SvncOpportunities.lobc) suncoooortunitv.ono© SvncProfileMetadata.rC) SvncTeam=ields.Job.ollC)SvncTeamMetadata.ol© UpdateOpportunitySpC UodateStage.ongM noalRicksMailboxN MeetinaRotlM Middleware(C) HandleHubsnotPatel in(c) RateLimited.onoD StreamingD Teamleleononyv C Userc) ChangeLmailjob.pho© DeactivateUserJob.phweollotowAhowcinlowaillieor© SetupDefaultsavedSei 106SyncTolntercom.phpc) sunc o? anhat.onoC) SuncToUserPilot.ohoC BaseProcessina.Job.oho@ Dummv.Job.php© ImportRecallAlRecordings 1o4© ImportRemoteTrackJob.p 10*C.lob.nhn©.JobDispatcher.php© JobDispatcherInterface.p110@ PuraeSoftDeletedOpportu 111#. SasVicibilitvControl.nhnlv D Listenersv D ActivitiesvM ActivityDrovidor3m luctealiv MllcorDilot© TrackProviderin: 118D1V8AVpublic function backoffO: arrayreturn [30, 90, 180]:* achrows conzalnertxceptzoninterrace* achrows Notroundexceptzoninterrace* dchrows Exception IhrowablepubLic tunction handlelAcrvTvreDosttory sactvitvrenostrorv.urmactvirvservice scrmactzvitvservzceConnection Sconnection.): void {Sactivity = SactivitvRenository->FindBvidSthis->activitvid:if (Sactivity === null) {throw new_InvalidArqumentExceotionm'MatchActivitvermbatal Cannot find activitv.')Itry 1Sconnection->transactionfunctionOuse Sactivitv. ScrmActivitvService. SactivitvRenositorv) <Loa: • infod messaaeInemote coanchl =s Cthic-SnemnteSeanch.'set_configuration' => Sthis->fromConfiguration?-›getIdO,Iold ctatel =s [llload idi =s Cactivitv-saotlead(12.sa0+td^)|'contact id' => Sactivity->getContactO?->getIdO.'account id' => Sactivity->getAccountO?->getIdo'opportunity id' => Sactivity->getOpportunityO?->getIdO.'stage id' => Sactivity->getStageO?->getIdoSthis->resetcrmMapoingsSactivitv. SactivitvRevositorv*Sthis->switchcrmconfzqurat.ion-NeededSactiv1tv):lelner Code will hoin INF to underctand vour Laravel ann code II Generate II Don't Show Anvmore (todav Q•08)=laravel.logA SF (jiminny@localhost]4 HS_local (jiminny@localhost]# console [PKob.# console [euJ# console [slAGiNg)[2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"neaders".?"Uace":L"Inu,or May 2020 14.21.15 6Ml"Jn"Transter-Encod1nq":"chunked")."Connection":"keep-alive""CF-Ray":L"9t80debödb60dcsa-S0F"J,"Strict-Transport-Secur1ty":"max-aqe=31536008* 1ncLudeSubDomains: preload")n"Vary":"orioin.accent-encodino""access-control-allow-credentials": ["false"J."server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\","x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"Set-Cookie":["__cf_bm=SrUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Renont-To"."","endpoints\":[{"unl".httns:la.nel.cloudflane.com./renon+W/v42c=NVA1cVTPQfVm32anS0#xVF/sd2RN"group\":\"cf-nel\","max_age\":604800}"],"NEL":["{\"success_fraction\":0.01,"report to\":|"cf-nel\"."max age":604800}"]"Server": ["cloudflare"]}} {"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab""trace_10":C/AD8565-905t-4604-9405-0e5b551e5545"helsuppon Dally • In zn 15 m100% Lz• Mon 11 May 12:41:04AskJiminnyReportActivityServiceTest vCascade• HubSpot Rate Limi+0 ..SidsToVerifvl = sactivity->oet1d0:wreturn Sidstoverity:Then in DeleteContactloh:•handle.•phpSidsToVerify = []:Sdb→>transaction function O use .. &SidsToVerify: void <fall cleanunSidsToVerify = Sthis->handleActivities(Sactivities, Sdispatcher, Slogger):Dispatch AFTER commiforeach (sidsToVerify as &id)VerifyActivityCrmTaskJob::dispatch(Sid):Effort: small. Impact: correctness (no orphan verify jobs from rolled-back transactions) + shorter transactionsMy recommendationImplement all three, in this order of rol:1. Option 1 first (10 min effort, prevents data drift today)2. Option 3 second (15 min effort, fixes a subtle correctness bug)3. Option 2 when you tackle batch endpoints generallyAsking question• Which to imnlement now?Which to implement now?Ada HandlaHubspotRateLimit middleware + retryUntil + maxExceptions + RateLimitException-aware loggin to VerityActivitvCrmTaskJob, Minimal changeOntion 1 + Ontion 3correctness bug,All threeOntions 1 4 2 4 introduce a new VerifvActivitiecCrmTackc.loh (batch) larder seone• neede a new inh clace and batch verify in the CPM cervice laverNone — just discussDon't implement yet; want to think through the trade-offs more before changing anythingOther answe÷ « CodeClaude Onus 4.7 MediumWN Windsurf Teams48.6UTE.8io 4 spaces...
|
PhpStorm
|
faVsco.js – SyncCrmEntitiesTrait.php
|
NULL
|
16913
|
|
15171
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
iTerm2ShellEditViewSessionScriptsProfilesWindowHelp(ahl| Daily - Platform • in 20 mADEV (docker)• *з.DOCKER881DEV (docker)882APP (-zsh)masterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY] laysJY-20698-fix-SF-activity-types-on-new-playbookJY-20543-AJ-report-trackingJY-20384-handle-auto-sync-with-no-access-to-event-typeJY-20458-ask-Jiminny-user-definitionsJY-19666-fix-import-contacts-account-associationJY-19666-HS-import-contacts-and-accounts-batch-jobJY-20458-Ask-Jiminny-ReportsJY-20200-batch-update-CRM-objects-SalesforceJY-19666-HS-webhooks-add-contact-and-companyJY-20348-trigger-setup-DI-layout-on-team-creationJY-20326-refactor-info-message-in-commandJY-20317-fix-auto-log-delay-issue-on-all-channels-disabledJY-20312-remove-on-update-change-last-synced-at-crm-configurationsJY-20306-SF-skip-auto-sync-for-task-based-playbookJY-20192-remove-deleted-team-from-saved-search-filtersJY-20197-import-opportunity-batch-jobJY-20293-enable-status-field-for-pipedrive-dealsJY-20191-remove-commands-interactive-promptsJY-20118-change-default-sync-strategyJY-20183-add-cache-on-auto-log-delayJY-20197-add-import-opportunity-batch-job20118-hs-opportunity-make-webhook-strategy-defaultJY-20118-make-default-hs-opportunity-sync-strategy-webhook-basedJY-20196-handle-opportunity-without-noteJY-20118-improve-opportunity-importJY-20189-handle-activity-search-on-deleted-groupsJY-20160JY-20145-filter-out-converted-leads-when-matchingJY-20150-skip-push-summary-on-summary-ready-1f-autologJY-20132-fix-note-encodingJY-19792-clean-logslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ devroot@docker_lamp_1:/home/jiminny# ]-zsh-zsh885100% C47 8• Mon 11 May 9:25:19181screenpipe"#6DEV...
|
PhpStorm
|
faVsco.js – MatchActivityCrmData.php
|
NULL
|
15171
|
|
15249
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
iTerm2•00ShellEditViewSessionScriptsProfilesWindowHelpDEV (docker)DOCKERO 81DEV (docker)882APP (-zsh)• *з.masterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY] laysJY-20698-fix-SF-activity-types-on-new-playbookJY-20543-AJ-report-trackingJY-20384-handle-auto-sync-with-no-access-to-event-typeJY-20458-ask-Jiminny-user-definitionsJY-19666-fix-import-contacts-account-associationJY-19666-HS-import-contacts-and-accounts-batch-jobJY-20458-Ask-Jiminny-ReportsJY-20200-batch-update-CRM-objects-SalesforceJY-19666-HS-webhooks-add-contact-and-companyJY-20348-trigger-setup-DI-layout-on-team-creationJY-20326-refactor-info-message-in-commandJY-20317-fix-auto-log-delay-issue-on-all-channels-disabledJY-20312-remove-on-update-change-last-synced-at-crm-configurationsJY-20306-SF-skip-auto-sync-for-task-based-playbookJY-20192-remove-deleted-team-from-saved-search-filtersJY-20197-import-opportunity-batch-jobJY-20293-enable-status-field-for-pipedrive-dealsJY-20191-remove-commands-interactive-promptsJY-20118-change-default-sync-strategyJY-20183-add-cache-on-auto-log-delayJY-20197-add-import-opportunity-batch-job20118-hs-opportunity-make-webhook-strategy-defaultJY-20118-make-default-hs-opportunity-sync-strategy-webhook-basedJY-20196-handle-opportunity-without-noteJY-20118-improve-opportunity-importJY-20189-handle-activity-search-on-deleted-groupsJY-20160JY-20145-filter-out-converted-leads-when-matchingJY-20150-skip-push-summary-on-summary-ready-1f-autologJY-20132-fix-note-encodingJY-19792-clean-logslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ devroot@docker_lamp_1:/home/jiminny# ]lablDaily - Platform • in 12 mA-zsh-zsh885100% C47 8• Mon 11 May 9:33:44181screenpipe"·6DEV...
|
PhpStorm
|
faVsco.js – Client.php
|
NULL
|
15249
|
|
16798
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
FinderFileEditViewGoWindowHelp<•00DEV (docker)DOCKERO ₴1DEV (docker)882APP (-zsh)|• жзmasterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ devroot@docker_lamp_1:/home/jiminny# ]• Support Daily • in 2h 33 m-zsh84-zsh885100% <78• Mon 11 May 12:27:41181screenpipe"0 ₴6DEV...
|
PhpStorm
|
faVsco.js – PlaybackController.php
|
NULL
|
16798
|
|
15007
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
PhostormFV faVsco.js~VIewINavicareCode%9 JY-20725-handle-HS-search-rate-limitroledey© RemoteCrmObjectn© ResponseNormalizeg service.onpg) syncrielaAction.onC) synckelatedAcuivilc) wednooksynebalc~ D IntegrationApp› D Accessors896C Api• contioDDTO• D FiltersHoosProsoectSearchstr• ServiceTraitsC) DataClient. oho©DecorateActivity.pt904 CC) LocalSearch.ohv© LocalSearchinterfac© RemoteSearch.php© Service.phpv D Listeners© ConvertLeadActivit© PurgeLookupCache911>D Metadata>D Migration> D Pipedrive© HubspotSyncStrategyBase.phpCachedcrmservicebecorator.onp© ProspectCache.phpС Cпескапокetrукemotematch.ong© MatchacuivitycrmData.ong© CrmActivityService.phpclass Service extends Baseservice 1mpLements* dreturn nulularrousLead|null,Accountlnulz.Opportunity|null,Contactlnul.Stage|nult,string|null=| A7 A47 X3 A y 15public function matchByDomain(string $domain, ?int $userId = null): ?array$companyName = $domain;// Try to find a company matching their email domain.ScompanyProperties = [countryInhone"name""hs_avatar_filemanager_key',11!=31Console,Log xChanaes 12 filed= env.local aon© Client.php app/Services/Crm/Hubspot© HandleHubspotRateLimit.php app/Jobs/Middleware© HubspotClientinterface.php app/Services/Crm/Hubspot© HubspotPaginationService.php app/Services/Crm/Hubspot/Pagination©JiminnyDebugCommand.php app/Console/Commandsphe logging.php config©MatchActivityCrmData.php app/Jobs/Crm© MatchCrmData.php app/Jobs/Activity/Import© PaginationState.php app/Services/Crm/Hubspot/Pagination© RateLimitException.php app/Exceptions© Service.php app/Services/Crm/Hubspot~ Unversioned Files 10 files= env.local.dak appE .env.nikilocal app= env.other apo|< → E, Side-by-side viewerDo not ignoreCurrent version tests/Unit/Policies/CanAccessAiReportsTest.phpHighlight words tx ?<?ohpdeclare(strict types=1)namespace Tests Unit Policlesuse Jaminny contracts Acu Permisszonenum•Jaminny Models TeamJiminny Policies UserPolicvuse Jiminny|Repositories\AutomatedReportsRepository;use PHPUnit\Framework\Mock0bject\Mock0bject;use puPllni+ Enamewonk Tecttase:C) CreateMockaskJiminnvReportResultCommand,oho apo/Console/Commands/ReF favicon.ico public= ids.txt aodTa raw_sql_query.sql appelper Code will help IDE to understand your Laravel app code. // Generate // Don't Show Anymore (moments ago)class CanAccessAiReportsTest extends TestCaseprivate AutomatedReportsRepository&Mock0bject $automatedReportsRepository;private UserPolicy $policy;laravel.log# console [PKOb.A console (EU]A SF jiminny@localhost]A console (STAGING]A HS_Jocal (jiminny@localhost]accept-encoding"],"access-control-allow-credentials": ["false"],"server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3)",cfr;desc=\"9f80deb8e7c6dc3a-IAD)""],"x-content-type-options": ["nosniff"],"x-hubspot-correlation-id" : ["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"Set-Cook¡e":["__сf_bm=SIUrtdQgXVc¿k50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],"керогс-10":"1enapolnus"."url":nccos:a.nel.cloudtlare.comredorcV4.S=NYALSVIPorymszorSUnxY24S0ZKh"max_age\":6048005"J,"NEL": ["{"success fraction":0.01.\"report_tol":\"cf-nell","max ade".604800-""Server": ["cloudflare"]f}{"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab" ,"trace id":"c7ab8365-903f-46d4-9403-0e5b551e3545"*|CascadeNew Cascade© HubSpot CRM Call Review© Investigating Rate Limit Errors© HubSpot Rate Limit ReviewAsk anything (2AL)+ <> CodeSAdaptive50 lil| Daily - Platform • in 37mAskJiminnyReportActivityServiceTestvA100%C&• Mon 11 May 9:08:59+0 ..Cascade Code & ••Kick oft a new oroiect. Make chancesacross vour entire codebase.W Windsurf Teams 908:62 UTF-8 P 4 spaces...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
15007
|
|
14999
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
PhostormFV faVsco.js~ViewINavicarecode%9 JY-20725-handle-HS-search-rate-limiroledey© TeamOwnerService.php© TeamService.php(C) TranscodeParameterResc© UserService.phpC) Uuid.pnp> D TraitsDUseCases> DUser> D Utils› D Validation© HubspotSyncStrategyBase.phpT SyncCrmEntitiesTrait.phpCachedcrmservicebecorator.onpphp nelpers.ongInitialFrontendState.php© Jiminny.php© Plan.phpC) Serializer.oho© TeamScimDetails.phpbootstrap> D build→ contio> O contribM database• M docsO front-end• C lang› [ node_modules library root> O phpstan> D public› Dresourcesv D routesphp api.phppnp api_vz.ongpnp console.ongpnp customer_api.pnppnp emoedded.onophp health.phpphp scim.phpphp web.phpphp webhook.php>Mscriots~ D storage•aoo> D debugbarM frameworkv Mloas.aitianoreel audio wav= cuctom loal© MatchActivityCrmData.php© CrmActivityService.php* RateLimitexception.png© MatchCrmData.phpclass Service extends BaseService 1mplements914931* dreturn nulularrousLead|null,Opportunity|null,ContactlnulaStage|nult,strinalnulpublic function matchByDomain(string $domain, ?int $userId = null): ?array$companyName = $domain;// Try to find a company matching their email domain.ScompanyProperties = [countryonone"name""hs_avatar_filemanager_key','industry' .l"hubspot_owner_id',ShsAccounts = sthis->cuient->aetinstanceol->comoanieso->search?vlomainScomnanvName. Scomnanv?ronerties)catch uthrowable se) *"ennont => Se->aetMessaaeolI"domain' => Sdomaininotunn null.937Saccount = null;// If there are multiple accounts, don't guess, we'll ask later.if (|count(ShsAccounts->data-›results) === 1) {// Persist this remote object.Saccount = $this->syncAccount($hsAccounts->data-›results[0]->companyId);E hubspot-journal-poll.log= laravel lodolner Code will hoin INF to underctand vour Laravel ann code II Generate II Don't Show Anvmore (maments aao)© ProspectCache.phpС Cпескапокetrукemotematch.ongм|×3 ^.II I IIII 1E custom.log xA SF jiminny@localhost]A HS_Jocal (jiminny@localhost]# console [PKOb.# console [euJ# console [slAGiNg)[2026-05-07 14:21:15] Local. INFO: [Hubspot] DEBUG Getting headers {"neaders".?"Uace":L"Inu,or May 2020 14.21.15 6Ml"Jn"Transter-Encod1nq":"chunked")"Connection":"keep-alive""CF-Ray" : ["9f80deb8db60dc3a-SOF"],"Strict-Transport-Security":["max-aqe=31536000: includeSubDomains: preload"].acceot-encodino"access-control-allow-credentials": ["false"],"server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\","x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtmOY-1778163675-[IP_ADDRESS]-May-26 14:51:15 GMT; domain=.hubapj.com; Http0nly; Secure; SameSite=None"],"Report-To" : ["{\"endpoints)":[{\"urz\":\"https:\V/\V/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RW\"group\" :\"cf-nell",\"max_age\":604800}"],"NEL" : ["{\"success_fraction\":0.01,\"report_to\":\"cf-nel\",\"max_age\":604800}"],"Server": ["cLoudflare"]H} {"correlation_1d":"95256555-ec98-4541-b9za-adta/sboyeab"."trace_10":C/AD8565-905t-4604-9405-0e5b551e5545"CascadeNew Cascade114 1111© HubSpot CRM Call ReviewC Investigating Rate Limit Errors© HubSpot Rate Limit ReviewAsk anything (38AL)+ « CodeC Adantive40 ll | Daily - Platform • in 37 mAskJiminnyReportActivityServiceTest100% (. • Mon 11 May 9:08:44+0 ..Cascade CodexKick off a new project. Make changesacross your entre codedase.WN Windsurf Teams014-24 UITE.8f?4 spaces...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
14999
|
|
15437
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
PhostormVIewINavicareCodeFV faVsco.js°9 JY-20725-handle-HS-search-rate-limroledey© BatchSyncCollectolyhuospotsyncstrategybase.ongCachedcrmservicebecorator.onp© ProspectCache.phpe balchsynckealsseС Cпескапокetrукemotematch.ongccloseaDealstagess @ MatchacuivitycrmData.ong© ermactivilyservice.phgDealrielasservice.gc)Decorateacuivilv.or© FieldDefinitions.phrclass Cllent extends Baseclient 1mpLements Hubspotcllentintertace- A2 A65 X1X1 ~C) FieldT vpeconvertee Hubspotclientinterc) Hubspotlokenman© PayloadBuilder.phpC) RemotecrmobiectP ResponseNormalizec) Service.onoC)SvncFieldAction.onC) SvncRelatedActivitC) WebhookSvncBatclv MintearationAorM Acceccors• D ConfigD DTO• M SiltersJobs• M ProcnectSoarchStr.W service lralts© DataClient.php© DecorateActivity.phcLocalsearch.oneu LocalSearchintertac© RemoteSearch.phpc) Service.phpv W Listeners© ConvertLeadActivitc) PurceLookuocache> M Metadata> Miarationa Pioedrivev Salesforce• D Fields• M OnnortunitvMatcheMOnnortunitvSvneSt897 (M ProsneetSearchStr.M ServiceTraitcC) Client nhr© DecorateActivity.ph. Delete@biectsTrait© FieldDefinitions.php© PayloadBuilder.php© Profile.php© QueryBuilder.phpououc tunction 1sunauthorizedzxcentionExcentionse: 000ureturn str contains(Smessage. "401 unauthorized')Istr contains(Smessage..'http 401') |1str_contains(Smessage, 'status code 401') |(orea match( pattern: • /\b401\b/' Smessage) &s str contains(Smessage, 'unauthorized')):* Validates and refreshes the access token if needed before API requests.* This ensures long-running processes don't fail due to token expiration.* @throws SocialAccountTokenInvalidExceptiony usagespublic function ensureValidToken: voidif (Sthis->oauthAccount === null) {Snewloken = sthis->tokenmanaqer->ensureval1dloken(sth1s->oauthaccountrif (SnewToken !== null) {sthis-›accessloken = snewloken:public function getConfigoreturn Sthis->confia:returns onlv active (archived=false)9 usadespublic function get0wners: arrayreturn $this->getNewInstance()->crm()->owners()->getALL();* apanam bool Sarchived* dretum arrau<ownens/r71s usages40 hlDally - Platrorm • now100% 4 • Mon 11 May 9:50:09U AskJiminnyReportActivityServiceTest v+0 ..11 1l1III=custom.log ^=laravel.logA SF (jiminny@localhost]4 HS_local [jiminny@localhost]# console [PKob.# console [euJ# console [slAGiNG)[2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {w19 .V"neaders".?"Uace":L"Inu,or May 2020 14.21.15 6Ml"Jn"Transter-Encod1nq":"chunked")."Connection":"keep-alive""CF-Ray" : ["9f80deb8db60dc3a-SOF"],"Strict-Transport-Secur1ty":"max-aqe=31536008* 1ncludeSubDomains: preload")naccent-encodino""access-control-allow-credentials": ["false"]."server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\","x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"So+-Cookie"." c+hm-Stlirtd0aXVr.kSandas6hzVVKhzTn0BidvMaheCtm0V-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Renont-To"."","endpoints\":[{"unl".httns:a.nel.cloudflane.com./nenon+|W/v42c=NVA1cVTPQfVm32anS0ixVF/sd2RI\"group)":\"cf-nel\","max_age\":604800}"],"NEL":["{\"success_fraction\":0.01,reportto. "cr-nel,"max age":604800}"]"Server": ["cloudflare"]}} {"correlation_1d":"95256555-ec98-4541-b9za-adta/Sb6Yeab","trace_10":"C/AD8565-905t-4604-9405-0e50551e5545I IIllC;CascadeHubspot Rate Limit Reif (Sretry) {sleenab:return $this->searchCallsForPeriodByPage($from, $to, $page, false);return null;Why this is now broken/suboptimal with the new client1. Covehes Encef lint Couk Be 1,0, o.) l tecuro d: we aiays sCcep ion that The now clioni carefly consirveted win rety after fiom headers in2. For tng te eage a mpy. The mont cen meon tweslor notsea th lil oer eit o - en oat , t aoi, od in trniscont aloe atry andtee siently3. The Sretry = false recursive flaa is fragile. Once we pass retrvefalse. on the second 429 we just return null without distinguishing rate limit from reaSuggestionCatch Ratel imitFycention cnecificallv and uco detRetrvifterd.D phppublic function searchCallsForPeriodByPage(Carbon strom, Carbon sto, int Spage, int sretries = 2)trydSpay Load = Sthis->payLoadbu1lder->generatesearchcaulsByPer1odPayLoad(Strom, Sto, Spage);return sthis->client->search'cals". Soavload):} catch (RateLimitException $e) {throw se: // hubble un: caller decidec whether to fail the imnort or releace the iohlsleen min Se->aetRetrvAftero, 30)):return $this->searchCallsForPeriodByPage($from, $to, $page, $retries - 1);} catch (Exception Sexception) {$this->logger->info('(HubSpot) Search calls for period failed', (...]);recurh nuet;only swallow non-rate-limit Tallures as beroreEven better — if searchCallsForPeriod is called from a queued job (which it typically is for backfills), don't swallow at all. Let RateLimitException bubble to thejob middleware (HandleHubspotRateLimit), which already handles release-with-delay properly. The in-process sleep() wastes a worker for up to 30s and ties upHorizon throughput.Let me check if it's job-driven:Coorchod caorsbColleGorDorindlrdingURLToken in app (.php) (5)Both callers are backaround workflows (a Console command and an internal service). So letting RateLimitException bubble to the iob middleware is the cleanestanswer - drop the sleep(1) retry path entirely and rely on HandleHubspotRateLimit:: release(Sdelay)TL:DR for #2: the sleep(1) predates the new structured exception. Either:• Catch RateLimitException and use getRetryAfter() (replace blind sleep(1) ), orLet it bubble to the job middleware and delete the in-process retry - preferred3. Whv matchExactlvBvEmail() Has No Rate Limit HandlinaCalle(erch d lstorPero itnypase/secrchdll forpernod /searchCalt9 eo adinguiLroten) it.on onyi6e handit 62-198 wil remove it from find and otherWN Windsurf Teams802•6UTF.RPo 4 spaces...
|
PhpStorm
|
faVsco.js – Client.php
|
NULL
|
15437
|
|
15186
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
PhostormVIewINavicareCodeKeractorFV faVsco.js?9 JY-20725-handle-HS-search-rate-limitroledey© SyncRelatedActivityManager.php© TrackRecordingFileSiz© TrackRecordingSizeEnT. ValidateSmitProspect:yhuospotsyncstrategybase.ongCachedcrmservicebecorator.onp© ProspectCache.phpAjReportsD Avatar0 CalendarConference0 Crm>@ Bullhorn>C CloseC Copper© MatchActivityCrmData.php© CrmActivityService.phg© MatchCrmData.phpclass Cllent extends Baseclient 1mpLements HubspotclientintertaceM | A2 A64 X1X1A Vpublicfunction 1sUnauthorizedexception(\exception se): bool848// BadRequest can contain 401 status codesreturn $e->getCode === 401;>J Crmobiects07 DecorateActivitv851• Dummy) Helpersv h HubspotAccountSvncStrate// Check for HTTP client exceptions with status codesif (Se instanceof \GuzzleHttp\Exception \RequestException && $e->hasResponseO) ‹Sresponse = $e->getResponseO:if (Sresponse !== null) {return Sresponse->getStatusCode === 401;II 1 IMШ>D Actionsa ContactsuncStratedm FieldsSmessage = strtolower(se->qethessageoo• M lournal1 Metadatalreturn str containsSmessage.'401 unauthorized') 11vOpportunitvSvncStstr contains(Smessage.i'http 401') 11• M Concerns.(c) Hubsnotl actMonstatus code 481')Corea match pattern'/\b401\b/', $message) === 1 && str_contains($message, 'unauthorized'))Console,Log XChanaes 12 filed= env.local aonTJ0 + → Side-by-side viewer •8 35f036ac app/Services/Crm/Hubspot/Client.phgDo not ignoreHighlight wordsx 13 B ?C) Client.oho aon/Services/Crm/Hubsooti© HandleHubspotRateLimit.php app/Jobs/Middleware© HubspotClientinterface.php app/Services/Crm/Hubspot© HubspotPaginationService.php app/Services/Crm/Hubspot/Pagination@ JiminnyDebugCommand.php app/Console/Commandsphp logging.php config© MatchActivityCrmData.php app/Jobs/Crm© MatchCrmData.php app/Jobs/Activity/Import© PaginationState.php app/Services/Crm/Hubspot/Pagination© RateLimitException.php app/Exceptions© Service.php app/Services/Crm/HubspotUnversioned Files 9 files* dthrows Badrequestreturn Sresponse->getStatusCode === 401:Check for Guzzle HTTP excentionsif (Se instanceof \GuzzleHtto\Exception\CLientException) {return Se->aetCode0 === 4015= env.nikilocal apoE.env.other app©) CanAccessAiReportsTest.php tests/Unit/Policies• CreateMockAskJiminnvReportResultCommand.php app/Console/Commands/Re// Fallback to string matching as last resort, but be more specifioSmecsanp = stntolowen(Se->aetMeççaae0)•ki tavicon.ico publicE ids txt apriaraw sol querv sall aool© SimulateWebhooksCommand.php app/Console/Commands/Crm/Hubspotneturn stn contains Smessade.'401 unauthorized') ||stn contains Smecsade'http 401') 11str_contains($message, "status code 401') |1(preg_match('/\b401\b/', $message) && str_contains(Smessage, 'unauthorized'));olner Code will hoin INF to underctand vour Laravel ann code II Generate II Don't Show Anvmore (18 minutes aao)1 Daily - Platform • in 19 m100% Lz• • Mon 11 May 9:26:05AskJiminnyReportActivityServiceTestv+0 ..=laravel.logA SF (jiminny@localhost]4 HS_local (jiminny@localhost]# console [PKob.A console [EU]A console [STAGING]accept-encoding"],"access-control-allow-credentials":["false"]."server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfr;desc=|"9f80deb8e7c6dc3a-IAD\""],"x-content-type-options": ["nosniff"],MMi9.У"x-nuospoc-correlacion-1d.l "0ryeuzd0-or0o-/812-p0ba-ooob/ccbseesr"ser-Lookle:ct.dm=sLurcaugxvrzksopacronzvyknzinubzavrabeccmoy-1//81050/5-1.0.207-May-26 14:51:15 GMT: domain=.hubapi.com: Http0nly: Secure: SameSite=None"],"керогс-10":"1endpolnts""url":nccos:a.nel.cloudtlare.comredorcv4?s=NYALsVIPorymszorsunxy24S0zk"max_age\":6048005"J,"NEL":["{"success fraction":0.01."max ade".604800-""Serven"•["cloudflare"]}} {"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab","trace id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}CascadeHubspot Rate Limit Re9. Matchcrmbata rate limiter move is logically correct but asymmetric with the quardMatchCrmData.oho:103-1131SrateLimiter->canMakeRequest (Sactivitv->oetcrmo))4$this->release(...)return;ScrmObjects = $crm0bjectsResolver->resolveFromCall(...):SrateLimiter→>incrementRequestCount(Sactivity->getCrm0));Movina increnent:RequestCount to after resolveFromCall is correct — previouslv it counted the attemot even if the call failed. However. resolveFronCall canmake multiple CRM API calls (email match + phone match + domain match). The rate limiter counts this whole resolver as 1 request. If a preventive rate limiter wereadded inside Client, the ProviderRateLimiter at the job level would count "1 request" while the client made 3 calls - so the two counters would diverge and thepreventive limiter would still be meaninaful independentlv.Rate Limit counter Interaction — vatchcrnbata vs Cllent-Side Preventive LimitThe question about how the ProviderRateLimiter would interact with a preventive client-side rate limit:Current flow MatchtmData:1. canMakeRequestlo checks the Laravel cache-oased counter + 1ob-level, coarse-arained, oer-cRM-contic2. resolveFromCall() makes 2-3 actual HubSpot API calls3. incrementR.If a preventive rate limit were added in Client (e.g. before search()):Ask anything (&AL)+ <> CodeSAdaptive11 differencesCurront vorcion* dchrows Badrequestreturn sresponse->qetstatuscode0 === 4015Smessage = strtolower(Se->aetMessage0)sreturn str contains(Smessage."401 unauthorized')str contains(Smessage.'htto 401') 11stn contains (Smessade.Istatus code 401')(onea match(i/\b401\h/1. Smescage) ea= 1 cc str contains(Smeccage. 'unauthonized!))•* Validates and refreshes the access token if needed before API requests.ts aetAccociationchatals 20mAl}, $toAssociations):Po 4 spaces...
|
PhpStorm
|
faVsco.js – Client.php
|
NULL
|
15186
|
|
16286
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
PhostormVIewINavicareCodeLaravelKeractorTOOISWindowmelpFV faVsco.js?9 JY-20725-handle-HS-search-rate-limitroledey© HubspotPaginationService.phpC. ActivitvProviderClientyhuospotsyncstrategybase.ongy syneermenttes tralt.onpCachedcrmservicebecorator.ong© ActivityProviderRegist© ActivityProviderServic© CallDenormalizerRegis© CrmOwnerResolver.ph© DatalmportHandlerinte© MeetingBotService.ph© ParticipantConsentSer© ParticipantsService.phT ResponseValidationTreT SalesforceGetUserTrai(© SfDenormaliserMainCr© TrackRecordingFileSizT DeleteCrmEntityTrait.php© MatchactivityermData.php© Job.php*RateLimitexception.pr) PaqinationContia.phgclass PaginationStatec) Trackkecoroingsizeen(© ValidateEmitProspectE <oAlReportsD Avatarw Calendaral ermM Bullhornm CloseCoobenN CrmObiects• DecorateActivitym DummiHelpersv M HubsnotAccountSuncStrate• D Actions• ContactSyncStrate!DDIe› D FieldsM.lourna0 Metadatav @ OpportunitySyncSti> 0 Concerns© HubspotLastMo(c) HubspotLastmoi© HubspotLastMorc) =uosootLastMo© HubspotLastMor 7(C) HubspotSinales€ HubspotSvncStr(C) HubsnotWebhocv M Padination© HubspotPaginati 82@ DaginationGonfic) DacinationState> M ProcnectSearchStr.> M Redicpublic functio,construct(public float $startTime = 0.0,public int $total = 0public int $offset = 01..3public function incrementRequestCount: void{...}s usagespublic function incrementTotalRecords: void{...h3 usagespublic function updateLastTokenCheck: voidi...}public function setTotal(int $total): voidi...}public function updateLastRecordId(?string SlastRecordId): void{...}public function setoffset(int Soffset): void{...}oublic function shouldLoaProqressio: 000lreturn Sthis->requestCount > 0 ∞x Sthis->requestCount % PaginationConfia:: PAGINATION LOG FREQUENCY === 0public function hasReachedSafetyLimit: boolf...hpublic function shouldValidateToken: boolf...}public function getElapsedSeconds: float{...}lelner Code will hoin INF to underctand vour Laravel ann code II Generate II Don't Show Anvmore (todav Q•08)• suppont Dally • In 3h 24m100% 47. • Mon 11 May 11:36:55AskJiminnyReportActivityServiceTestvDO :+0 ..A SF (jiminny@localhost]4 HS_local (jiminny@localhost]# console [PKOb.# console leu)# console [slAGiNg)2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"Vace". "Inu,ur May 2020 14.21.19 6Ml"Jn"concenc-lyoe. apolicacion/ison.charser=utt-on"Transfer-Encoding": ["chunked"]."CF-Ray":"9t80deb8dbo0dcsa-S0F"J,"CF-Cache-Status": L"DYNAMIC"J,"Strict-Transport-Secur1ty":"max-aqe=31536000* 1ncludeSubDomains: preload")"access-control-allow-credentials": "false"."server-timing": ["hcid;desc=|"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfr;desc=|"9f80deb8e7c6dc3a-IAD\""],"x-content-tvoe-ootions":"nosniff"."x-hubsoot-correlation-id":"019e02d0-6fd8-7812-bdba-885b7ccb3ee3"]"Set-Cookip"." c+hm=Stlirtd0aXVr.kSandas6hzVVKhzTn0BidvMaheCtm0V-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Renont-To".f"s"endnoints".("url\":"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RV("group\":\"cf-nel\".("max_age\":604800}"],"NEL"L"1"success_fraction\":0.01,"reportco. "cr-nel"max agel ":604800}"].'Server": ["cloudflare"]}} {"correlation_1d":"95256555-ec98-4541-b9za-adta/Sboyeab","trace_10":"C/AD8565-905t-4604-9405-0e5b551e5545CascadeHubspot Rate Limit ReWhat chanaed and what didn'tImproved dramatically• HubSpot API quota burned: 441k → 11k. No risk of escalation to TEN SECONDLY ROLLING or DAILY LIMIT• Loa volume: 882k → 10k entries. Observability pioeline survives.• DB transaction churn: 245/s → ~50-100/s. ~3x reduction.• Worker CPU Redis load: vastly reduced (no APl HTTP overhead in 95% of cvcles).• Other queue jobs: still starved, but workers loop faster, so more cycles available - somewhat better.•DAILY LIMIT scenario: now fails immediately via siob->fail() instead of looping for 30 minStill bad (unchanged)•91% iob failure rate after 30 min. The fundamental bottleneck is HubSpot's 5 RPS + 30-min retrvlnt il. With 100k iobs throuch 5/s. vou need >5 hours• Activities end un in oridinal (ore-match) state, since failledo onlv loasWhat would still help (next steps, if relevant)1. Dispatch-side throttling: don't dispatch all 100k at once. The math hard-caps you at 5/s x seconds-in-window. Either pace the dispatcher (e.g. drip 4/s intoqueue) or use a single batch processor that honors the rate limit naturally,2. Bump RETRY_WINDOW_MINUTES : 30 min is way too short for 100k jobs at 5 RPS. To absorb the whole batch you need ~6 hours. But long-held unique locks aretheir own concern,3. Backtill via batch endpoints: HubSpot has batch read endpoints (100 |Ds per call) for contacts/companies/deals. They count as 1 call against the rate limitКОСТВСТЕСIООЕТИТСИКУNАМОТБE ВАРЬОЛОВTОTОRTCEEOCON/OEОEIAEIОВVATOACIAETEЛAEAIIECОNPRTOTEACО1IOSummaryImplemented• RateLimitException carries policy, exposes 1sDa1lyLimito v RateLimitException.php:9-33• Client:: executeRequest now has a per-portal Redis cache circuit-breaker: populates from real responses & Client.oho:76-119•Client::parsePolicy extracted: policy passed to exception v Client.php:166-184• Middleware fails fast on DATLY LIMIT• droos MAX RATE LIMIT ATTEMPTS • raised MIN RETRY DELAY to 5s with litter samoled loaaina V Handl eHubsootRatelimit.php:14-53• MatchActivityCrmData uses RETRY_WINDOW _MINUTES constant; skips stack-trace log for RateLimitException v MatchActivityCrmData.php: 32-78Not changed (per-portal redis cache replaces it): the DB rate limits table dependency. The new flow doesn't read from it. Existing ProviderRateLimiter usagein non-HubSoot code oaths (Salesforce, etc.) is untouched.Mot roenlt for tho 100k coonorin.• ~98% reduction in wasted HubSpot API calls• V ~99% reduction in loa volume• • DAILY LIMIT now triggers immediate fail (no 30-min loop)• • No more thunderina herd•/ 010 inh failuro rato ic unchanaod - fundamontallu a dicnatch-rato / rotrvlinti1 micmatch arahlom not a rato-limit-handlina nrohlom4 files +91-33)Accent alliCh 1 00 0. F vie con one wintai miake alo o o K Ve e i fatet So rit ik Che hol Gatly policy, Pory ot wc naid t ssmf to the - xopi0n)W Windsurf Toams 60-28 (17 charc) UTF.8io 4 spaces...
|
PhpStorm
|
faVsco.js – Client.php
|
NULL
|
16286
|
|
16419
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
PhostormViewINavicareCodeFV faVsco.js°9 JY-20725-handle-HS-search-rate-linProiect© SyncRelatedActivityManager.php© TeardownStream.php• AiAutomationAjReports> D AudioAutomatedReports© RequestGenerateAskJi© RequestGenerateRepo© SendReportExpiringSo© SendReportJob.php© SendReportMailJob.ph© SendReportNotGenera> [ Calendar0 Crmv _ Delere© DeleteAccount.Job.l© HubspotSyncStrategyBase.phpCachedcrmservicebecorator.onp© ProspectCache.php© MatchActivityCrmData.php*RateLimitexception.php© HandleHubspotRateLimit.php xC) PaqinationConfia.php* Job middleware that catches RateLimitException from HubSpot API calls* and releases the job back to the queue with the appropriate delay2 usagesclace HandloHuheno+Patel imitC) DeleteContact.Job.rTDeleteCrmEntitviraC) DeleteleadJob.ohr© DeleteOpportunityC) VeritvActivitvermirm Hubsoot• M Salesforce© AutologDelayedToCrm 20© CheckAndRetryRemoti 21© CreateFollowupActivit: 22(c) CroateNotec nhnl© MatchActivitiesToNew 24(C) MatchA ctivitvCrmDate(e [EMAIL]© saveAcuivity.onp© SaveTranscription.php© SetupLayout.php© SyncActivity.php© SyncFieldMetadata.ph© SyncHubspotObiects.r© SyncLeads.php© SyncObjects.php© SyncOpportunities.Job© SyncOpportunitv.phr© SyncProfileMetadata.rprivate const int MAX RETRY DELAY = 600:private const Int MIN KEIKY UELAY = 11private const int MAX_RATE_LIMIT_ATTEMPTS = 20;Renect1 usageprivate const int JITTER SECONDS = 5:nublic function handlecobiect Siob. callable Snext): voidtry {Snext(Siob):} catch (RateLimitException $e) {if (Siob->attemots() >= self::MAX RATE LIMIT ATTEMPTS) {Rate limit attemot limit reached. giving up'. [Inate limit meccade!=> $e->getMessageO,D:throw se:$delay = max( value: self::MIN_RETRY_DELAY, min($e->getRetryAfterO$delay += random_int(0, self::JITTER_SECONDS)...values: self::MAX_RETRY_DELAY)):SretrvAften = Se->aetRetrvAfterolCdolav = mayicolf:*MTN PETPV NCIAV minCnotnviften colf.•MAY RETRY NELAVDEc) Svncireampields.00.ol© SvncTeamMetadata.of(C) Uodate@ooortunitvSoN DealRisksLog::info('[HandleHubspotRateLimit] Rate limit caught, releasing job with delay'. ["nodclass=5100:.class.'attemots' => S1ob->attemotsol=> SretrvAfter.= Sdelav.Inate 1imit messadel => Se->ae+MecsadeOriM Meetina3o1M Middleward• Landle-ubsnotPatelin(C) Patel imited nhn> M StreaminalSattemots = Siob->attemotso:if (Sattemots <= 3 |I Sattemots % 10 === 0) $Log:: infof message: HIHAcceptFlle za tel iReiect riatseLimit caughtrergleasing job with delay'. I'oh class' => Siooumassi=custom.log~A SF (jiminny@localhost]4 HS_local (jiminny@localhost]# console [PKob.# console leu)# console [slAGiNg)2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {headers'1"Vace". "Inu,ur May 2020 14.21.19 6Ml"Jn"concenc-lyoe. apolicacion/ison.charser=utt-on"Transfer-Encoding": ["chunked"]."CF-Ray":"9t80deb8dbo0dcsa-SOF","CF-Cache-Status": L"DYNAMIC"J,"Strict-Transport-Secur1ty":"max-aqe=31536000* 1ncludeSUbDomains: preload"),acceot-encodino"."access-control-allow-credentials": "false"i."server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfr;desc=|"9f80deb8e7c6dc3a-IAD\""],"x-content-tvoe-ootions":"nosniff"."x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"Set-Cookip"." c+hm-Stlirtd0aXVr.kSandas6hzVVKhzTn0BidvMaheCtm0V-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Renont-To".f"s"endnoints".("url\":"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RW|("group\":\"cf-nel\".("max_age\":604800}"],"NEL":["{"success_fraction\":0.01,reportto. "cr-nel,"max agel ":604800}"].'Server":["cloudflare"]}} {"correlation_1d":"95256555-ec98-4541-b9za-adta/Sboyeab","trace_10":"C/AD8565-905t-4604-9405-0e5b551e5545suppont Dally • In sn 10m100% 2• Mon 11 May 11:50:23AskJiminnyReportActivityServiceTest -CascadeHubspot Rate Limit Re+0 ..ReasonRateLimitException.phpRemoved policy field & methodsMiddleware doesn't need it: cache TTL handles DAILY naturallycache stores scalar int retry after) instead of arraySimpler: no policy to trackDrop policy from RateL1m1tException constructorMatch new exception signature; still log policy for observabilityRemoved DAILY LIMIT branchretryUntil + long cache TTL handle it; saves complexityMIN RETRY DELAY 5→1Named JITTER SECONDS constantSelf-documentingCollapsed dual catch into single catch + instanceofMore readable; no awkward empty rethrow blockHow DAILY LIMIT now flows (no special case needed)1. HubSpot returns 429 with policyName: DAILY_LIMIT2. parseRetryAtter sees no Retry-After header, falls through to policy table → returns 600s (the DAILY_LIMIT detault lleft in parseRetryAfter)3. Cache populated with TTL=600 (10 min)4. All subsequent requests fast-fail via cache for 10 min - no API calls5. Middleware releases iohs with delav 1-6c (chean evcles. all hit cache)6. After 30 min, retryUntil expires → jobs permanent-fail naturally7. No special branch. no siob→>failo, no excention fieldThe system converges to the same outcome with less code.Re-running the 100k scenario (delta from previous run)Material chandes vs the previous version:• Job retry cycle is faster (delay 1-6s instead of 5-10s) → ~2x more queue cycles per second per worker• More cache hits per second (since cycles are faster) - but cache GETs are cheap (~0.1ms)• Same throughout ceilina (5 successful calls/s — HubSoot's limit)• Same final outcome (29k succeed 201k fail at T-20min)MetricSuccessful jobs in 30minPrevious (this round)This round9,000Wasted HubSpot API calls~10,800Job pop cycles/sec~50-1009,000~10,800~100-250|Log entries (with sampling)0000.~10.000Averade delav ner releace275gThe faster retry cycle gives you slightly better responsiveness when the cache window expires (more "lottery tickets" at HubSpot's open second), but doesn'tThe fundamental remaining issue is unchanged: 30 min x 5 RPS = 9k jobs ceiling. To process all 100k, you either need ~6 hours window, or batch-endpointredecian. or disnatch-side throttlingG al ... (2 files with chanaesann/lohe/Crm/MMatchActivitvCrmData.nhn 412-8View allapp/Jobs/Middleware/ HandleHubspotRateLimit.php +12 -20ot/m Client.oholReiect allAccent alliOk explain $delay += random int(0, self«JITTER SECONDS): It also seems that before the and then lets run the scenario again.Claude Onus 4.7 MediumW Windsurf Toams 26-12 (46 charc)UTE.8io 4 spaces...
|
PhpStorm
|
faVsco.js – HandleHubspotRateLimit.php
|
NULL
|
16419
|
|
16599
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
PhostormcodeFV faVsco.jsroledey© TrackRecordingFileSiz© ProspectCache.php© TrackRecordingSizeEnT. ValidateSmitProspect:AjReports© MatchacuivitycrmData.ong* RateLimitex0 Calendarn Conference(C) ProviderRateLimiter.phpC) PaqinationConfia.php0 Crmclass Cuient extends BasecLient imolements Hubspotcuientinterface@ bullnornJ close_copper>J Crmobiects_ DecorareAcuivily• DummyHelpersv h HubspotAccountSvncStrate> Actionsa ContactsvncStraterm Fields• Malournal1 Metadatalv OpportunitySyncSt• MConcerns.(c) Hubsnotl actMoC HubspotLastMo(C) Hubsnotl actMo(C) Hubsnotl actMo(C) Hubsnotl actMo© HubspotSingleSo UnhenotCunaCtr© HubspotWebhoov M Padination© HubspotPaginat© PaginationConfi(C) PaqinationState> D ProspectSearchStr:› D Redisv D ServiceTraitsTOnoortunitvsvnd() SvncCrmEntitiesT SuncFieldstirait.() WriteCrmTrait.ol 106• M UtilsM Webhook@ BatchSvncCollectol 1091101(c) RatchSvncRedisSerc) Client nhr(C) ClocedDea|StagocS 111@ Dea|FieldcService r 112* othrows RateLimitexceptzon1 usaaelorivate function executeReguest(callable SaoicalbiScachekev = Sthis->aetRateLimitCacheKevo:ScachedRetryAfter = Redis::get(ScacheKey):if (is_string($cachedRetryAfter) && is_numeric(ScachedRetryAfter)) {throw new RateLimitException('Hubspot rate limit (cached circuit-breaker)',int ScachedRetnvAftentryfrecurn sapllallor} catch (Throwable $e) {if (Sthis->isHubspotRateLimit(Se)) {sretryAtter = sth1s->parseretryAtterseRedis::setex(ScacheKev. SretrvAfter. (string) SretrvAfter):Sthis->loo->warnina(' Hubsoot Received 429 from APT"."confia id'= sthis->confio->aetido.policv= Sthis->oarsePoLicv(Se).= Se->aetMessadeOlthrow new RateLimitException( message: 'Hubspot returned 429', SretryAfter, $e);throw $e;1 usageprivate function getRateLimitCacheKey: stringreturn sprintf( format: 'hubspot:ratelimit:portal:%d'. Sthis->confiq->qetIdO):olner Code will hoin INF to underctand vour Laravel ann code II Generate II Don't Show Anvmore (todav Q•08)• suppont Dally • In 2n o0m100% Lz• Mon 11 May 12:10:07AskJiminnyReportActivityServiceTest v+0 ..CA2A6 X1X3A11111A SF (jiminny@localhost]4 HS_local (jiminny@localhost]# console [PKob.# console leu)# console [slAGiNg)2026-05-07 14:21:15] local.INF0: [Hubspot] DEBUG Getting headers {"Vace". "Inu,ur May 2020 14.21.19 6Ml"Jn"concenc-lyoe. apolicacion/ison.charser=utt-on"Transfer-Encoding": ["chunked"]."CF-Ray":"9t80deb8dbo0dcsa-S0F"J,"Strict-Transport-Secur1ty":"max-aqe=31536000* 1ncludeSUbDomains: preload"),"access-control-allow-credentials": "false"."server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfr;desc=|"9f80deb8e7c6dc3a-IAD\""],"x-content-tvoe-ootions":"nosniff"."x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"Set-Cookip"." c+hm=Stlirtd0aXVr.kSandas6hzVVKhzTn0BidvMaheCtm0V-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; Http0nly; Secure; SameSite=None"],"Report-To":["{("endpoints\":[{("url\":"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RV("group\":\"cf-nel\".("max_age\":604800}"],"NEL"L"1"success_fraction\":0.01,reportto. "cr-nel,"max agel ":604800}"].'Server": ["cloudflare"]}} {"correlation_1d":"95256555-ec98-4541-b9za-adta/Sboyeab","trace_10":"C/AD8565-905t-4604-9405-0e5b551e5545-31CascadeHubspot Rate Limit Re$cachedRetryAfter = Redis::get($cacheKey);1 recurns string latse nuce1T (1s string(scachedRetryAtter) ox 1s numeric(scachedretryAtter)) ...Ked1s::setex(scacheney, srecryarter, (string) srecryarter);Single atomic Redis com.Kev implementation notes1. SETEX is atomic - sets the value and TTL in one round-trip. (put internally does this too, but adds prefix manipulation and serialization in PHP-land2. No prefix from Laravel cache confia. Your key in Redis will be exactiy hubspot:ratelimit:portal:42. not cache prefix:laravel cache:hubspot:ratelimit:portal:42 . Easier to inspect with redis-cli. Make sure no other code is using a key like that - unlikely with this namespace3. Return value handlingRedis::aet(Snonexistent) → returns null (Predis) or false (PhpRedis)• The is strina(sy) &c ic numeric(sy) quard handles both cases olus malformed values cleaniv.4. Connection: uses Laravel's default Redis connection ( config/database.php → redis.default ). If you want to isolate this from queue/cache traffic, use Redicaoconnection("rate limitel)_soet(...) after definina a senarate connection5. Type cast (string) on store: setex requires a string value. Without the cast, PhpRedis throws a TypeError on intCache::aet/putRedis::aet/setex1combined)PHP CPU per op~50-100us (CacheManager + serialize)~10-20us (direct Redis cmd)Network bytes (value)~10 bytes (1:1:)1byte ("1")Key lengths0 chars (with orefix)lalAhoreNealigible per-call, but at 1,500 cache GETS/sec (steady state from previous trace), the savinas add up: ~50ms CPU sec freed, plus simpler Redis monitorina.SummarvSentrv imnact for 100k storm:• ~91.000 events to Sentrv all arouned under MaxAttenntcFyceededFycent ion• Will hit sentry rate-limits: events aet aropped~10% of monthlv quota on a tvnical small olan.• Recommended fix: add RateLimitException (and optionally MaxAttemptsExceededException) to the dontReport array in app/Exceptions/Handler.phpRedis swao doneCache::aet /out → Redis::aet/setex• Direct atomic no cerialization overhead• Same loqical behavior. leaner imolementation• Kev visible as olain hubsoot: ratelimit:nortal-fidl in redis-c14l11 111 1Ok what will happen if there is 10 workers. Once the ratelimit is cought and cache set by one, what will happen it the oth stilll.+ « CodeClaude Onus 4.7 Medium.nl .io 4 spaces...
|
PhpStorm
|
faVsco.js – Client.php
|
NULL
|
16599
|
|
16598
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
SlackFile Edit ViewGoHistoryWindowHelp000DOCKER₴1DEV (docker)882DEV (d)APP (-zsh)• xзmasterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY]@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-Lirroot@docker_lamp_1:/home/jiminny# ]HomeDMsActivityFilesLater..•More(aolSupport Daily • in 2 h 50 ml100% C8• Mon 11 May 12:10:07ED→Describe what you are looking forJiminny ...crsmecruus# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...0 Direct messagesa. Stefka Stoyanova€. Vasil Vasilevo Nikolay Ivanov. Galya DimitrovaAneliya Angelova, .... Stoyan TanevVes®. Aneliya Angelova& James GrahamE Lukas Kovalik y...:: AppsJira CloudLToastGoogle Cale...Stefka Stoyanova• Messages7 Untitled+C Files7 Untitledluesaay, April 28th ~Today ~Stefka Stoyanova 10:08 AMЛукаш, щом пре-рефайнмънта и рефайнмънтаще са само за МСР ако искаш не идвай да сигубиш времетоLukas Kovalik 10:12 AMда, няма да идвамStefka Stoyanova 11:35 AMЛукаш, ще сложиш ли естимейт наhttps://jiminny.atlassian.net/browse/JY-20818Jira Cloud -Move Ask Jiminny reports to separate...Bug JY-20818 in Jira CloudStatusDeployedPriority= MediumAssigneeLukas Koval...As of today at 11:35 AMOpen in Jira* SummariseMessage Stefka Stoyanova......
|
PhpStorm
|
faVsco.js – Client.php
|
NULL
|
16598
|
|
16551
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
SlackFileEditViewGoHistoryWindowHelpDOCKERO 81DEV (docker)882DEV (d)APP (-zsh)• xзmasterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY] laysJY-20698-fix-SF-activity-types-on-new-playbookJY-20543-AJ-report-trackingJY-20384-handle-auto-sync-with-no-access-to-event-typeJY-20458-ask-Jiminny-user-definitionsJY-19666-fix-import-contacts-account-associationJY-19666-HS-import-contacts-and-accounts-batch-jobJY-20458-Ask-Jiminny-ReportsJY-20200-batch-update-CRM-objects-SalesforceJY-19666-HS-webhooks-add-contact-and-companyJY-20348-trigger-setup-DI-layout-on-team-creationJY-20326-refactor-info-message-in-commandJY-20317-fix-auto-log-delay-issue-on-all-channels-disabledJY-20312-remove-on-update-change-last-synced-at-crm-configurationsJY-20306-SF-skip-auto-sync-for-task-based-playbookJY-20192-remove-deleted-team-from-saved-search-filtersJY-20197-import-opportunity-batch-jobJY-20293-enable-status-field-for-pipedrive-dealsJY-20191-remove-commands-interactive-promptsJY-20118-change-default-sync-strategyJY-20183-add-cache-on-auto-log-delayJY-20197-add-import-opportunity-batch-job20118-hs-opportunity-make-webhook-strategy-defaultJY-20118-make-default-hs-opportunity-sync-strategy-webhook-basedJY-20196-handle-opportunity-without-noteJY-20118-improve-opportunity-importJY-20189-handle-activity-search-on-deleted-groupsJY-20145-filter-out-converted-leads-when-matchingJY-20150-skip-push-summary-on-summary-ready-1f-autologJY-20132-fix-note-encodingJY-19792-clean-logslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-Lirroot@docker_lamp_1:/home/jiminny# ]HomeDMsActivityFilesLater..•More(aol§ Support Daily - in 2h 57 m100% C8• Mon 11 May 12:03:59ED→Describe what you are looking forJiminny ...crsmecruus# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...0 Direct messagesa. Stefka Stoyanova€. Vasil Vasilevo Nikolay Ivanov. Galya DimitrovaAneliya Angelova, .... Stoyan TanevVes®. Aneliya Angelova& James GrahamE Lukas Kovalik y…..:: AppsJira CloudLToastGoogle Cale...Stefka Stoyanova• Messages7 Untitled+C Files7 Untitledluesaay, April 28th ~Today ~Stefka Stoyanova 10:08 AMЛукаш, щом пре-рефайнмънта и рефайнмънтаще са само за МСР ако искаш не идвай да сигубиш времетоLukas Kovalik 10:12 AMда, няма да идвамStefka Stoyanova 11:35 AMЛукаш, ще сложиш ли естимейт наhttps://jiminny.atlassian.net/browse/JY-20818Jira Cloud -Move Ask Jiminny reports to separate...Bug JY-20818 in Jira CloudStatusDeployedPriority= MediumAssigneeLukas Koval...As of today at 11:35 AMOpen in Jira* SummariseMessage Stefka Stoyanova......
|
PhpStorm
|
faVsco.js – Client.php
|
NULL
|
16551
|
|
14980
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Term2ShellEditViewSessionProfilesWindowHelp(ahlDaily - Platform • in 38 m100% <78• Mon 11 May 9:07:59DOCKER (docker-compose)• *3181DOCKERDEV (-zsh)О 882APP (-zsh)L1DOCKER (docker-compose)QbdHhS--oxdRRkJZGww}{[IP_ADDRESS]{[IP_ADDRESS]:9300}{cdhilmrstw}{ml.machine_memory=4109217792, xpack.installed=true,transform.node=true,ml.max_open_jobs=20}]}" }elasticsearch1 {"type":"timestamp":"2026-05-11T06:07:11,100Z","level": "I"component":"o.e.c.s.ClusterApplierService""cluster.name" :"docker-cluster"ode.name":"e802ad473a4f""message": "master node{previous (], current [{e802ad473a4f}{e2ZKzgw4Q4aCf2w51jWr1A}-{ORUQbdHhS--OxdRRkJZGww}{[IP_ADDRESS]}{[IP_ADDRESS]:9300}{cdhilmrstw}{ml.machine_memory=4109217792, xpack.installed=true,transform.node=true,x_open_jobs=20}]}, term:239, version: 8756, reason: Publication{term=239, version=8756}}elasticsearchI {"type":"timestamp": "2026-05-11T06:07:11,170Z", "level": "INFO", "component":"o.e.h.AbstractHttpServerTransport""cluster.name":"docker-cluster""node. name":"e802ad473a4f""message":"publish_address{[IP_ADDRESS]:9200}, bound_addresses {[::]:9200}","cluster.uuid": "8uhZw1CUSGyWYR_OvaKx6g","node.id": "e2ZKzgw404aCf2elasticsearch1 {"type":"server""timestamp" :NFO""component":"o.e.n.Node""cluster.name":"2026-05-11T06:07:11,171Z","level": "I"docker-cluster""node. name":"e802ad473a4f""message": "started", "cluster.uuid": "8uhZw1CUSGyWYR_OvaKx6g","node.id": "e2ZKzgw4Q4aCf2w51jWr1A" }elasticsearchI {"type": "server""timestamp": "2026-05-11T06:07:11, 655Z""level":"INFO","component":"o.e.l.LicenseService","e802ad473a4f""cluster.name":"docker-cluster","node.name""message": "license [85e882e5-5714-4173-a5dd-9baa841494a0] mode] -valid", "cluster.uuid": "8uhZwICUSGyWYR_OvaKx6g", "node.id": "e2ZKzgw4Q4aCf2w51jWr1AI {"type": "server", "timestamp": "2026-05-11T06:07:11,665Z","level": "INFO", "component": "o.e.g.GatewayService","docker-cluster""node. name": "e802ad473a4f"., "message": "recovered [15] indices into cluster_state","cluster.uuid": "8uhZw1CUSGyWYR_OvaKx6g", "node.id": "e2ZKzgw4Q4aCf2w51jWr1A"1 t=2026-05-11T06:07:12+0000 lvl=warn msg="failed to open private leg" id=bbbf4561a337 privaddr=lamp:3080 err="dial tcp [IP_ADDRESS]:3080: connect: connection reft=2026-05-11T06:07:15+0000 lvl=warn msg="failed to open private leg" id=5c5a6ebcfad1 privaddr=lamp:3080 err="dial tcp [IP_ADDRESS]:3080: connect: connection refelasticsearchI {"type": "server""timestamp": "2026-05-11T06:07:15,845Z", "level": "I"component":"o.e.c.r.a.AllocationService","e802ad473a4f""cluster.name":"docker-cluster""message": "Cluster health statuschanged from [RED] to [YELLOW] (reason: [shards started [[activities_testing][0]]]).", "cluster.uuid": "8uhZw1CUSGyWYR_OvaKx6g","node.id":"e2ZKzgw4Q4aCf2w51jWr1A"| 1:M 11 May 2026 06:07:22.494 * DB loaded from append only file: 28.805secondsredis| 1:M 11 May 2026 06:07:22.494 * Ready to accept connections-zsh84-zsh12PROD (-zsh)'24.04.4 LTS' available.'do-release-upgrade' to upgrade to it.885screenpipe"System restart required ***Last login: Mon Apr 27 07:45:27 2026 from 212.5.153.87Last login: Thu May7 09:29:14 on consolePoetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parents@Lukas-KovaliMaсBook-Pro-Jiminny ~ $ I|T4STAGE (-zsh)*** System restart required ***Last login: Tue Apr 28 06:25:10 2026 from 212.5.153.87lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ |T5 QA (-zsh)Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parents- $I16 FE (-zsh)Poetry could not find a pyproject.toml file in /Users/lukas or its parentsO 86PRODSTAGEFRONTENDPoetry could not finda pyproject.toml file in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ ||X 27 EXT (-zsh)Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not finda pyproject.toml file in /Users/lukas or its parentsukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ lEXTENSIONView in Docker Desktop@ View ConfigEnable Watch...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
14980
|
|
15227
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
iTerm2•00ShellEditViewSessionScriptsProfilesWindowHelpDEV (docker)DOCKERO 81DEV (docker)882APP (-zsh)• *з.masterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY] laysJY-20698-fix-SF-activity-types-on-new-playbookJY-20543-AJ-report-trackingJY-20384-handle-auto-sync-with-no-access-to-event-typeJY-20458-ask-Jiminny-user-definitionsJY-19666-fix-import-contacts-account-associationJY-19666-HS-import-contacts-and-accounts-batch-jobJY-20458-Ask-Jiminny-ReportsJY-20200-batch-update-CRM-objects-SalesforceJY-19666-HS-webhooks-add-contact-and-companyJY-20348-trigger-setup-DI-layout-on-team-creationJY-20326-refactor-info-message-in-commandJY-20317-fix-auto-log-delay-issue-on-all-channels-disabledJY-20312-remove-on-update-change-last-synced-at-crm-configurationsJY-20306-SF-skip-auto-sync-for-task-based-playbookJY-20192-remove-deleted-team-from-saved-search-filtersJY-20197-import-opportunity-batch-jobJY-20293-enable-status-field-for-pipedrive-dealsJY-20191-remove-commands-interactive-promptsJY-20118-change-default-sync-strategyJY-20183-add-cache-on-auto-log-delayJY-20197-add-import-opportunity-batch-job20118-hs-opportunity-make-webhook-strategy-defaultJY-20118-make-default-hs-opportunity-sync-strategy-webhook-basedJY-20196-handle-opportunity-without-noteJY-20118-improve-opportunity-importJY-20189-handle-activity-search-on-deleted-groupsJY-20160JY-20145-filter-out-converted-leads-when-matchingJY-20150-skip-push-summary-on-summary-ready-1f-autologJY-20132-fix-note-encodingJY-19792-clean-logslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ devroot@docker_lamp_1:/home/jiminny# ]lablDaily - Platform - in 16 mA100% C47 8• Mon 11 May 9:29:47181-zsh-zsh885screenpipe"0 ₴6DEV...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
15227
|
|
15090
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
iTerm2•00ShellEditViewSessionScriptsProfilesWindowHelpDEV (docker)DOCKERO 81DEV (docker)882APP (-zsh)• жзmasterJY-20818-move-AJ-reports-to-separated-datadog-metricJY-20773-fix-automated-reports-user-pilot-trackingJY-20157-AJ-report-not-send-notificationJY-20508-notify-before-AJ-report-expirationJY-20372-ai-reports-promotion-pagesJY-20352-sync-opportunities-without-a-local-owner-user-id-is-nullJY-20738-debug-AJ-tracking-UPJY-18909-automated-reports-ask-jiminnyJY-20692-fix-integration-app-[API_KEY] laysJY-20698-fix-SF-activity-types-on-new-playbookJY-20543-AJ-report-trackingJY-20384-handle-auto-sync-with-no-access-to-event-typeJY-20458-ask-Jiminny-user-definitionsJY-19666-fix-import-contacts-account-associationJY-19666-HS-import-contacts-and-accounts-batch-jobJY-20458-Ask-Jiminny-ReportsJY-20200-batch-update-CRM-objects-SalesforceJY-19666-HS-webhooks-add-contact-and-companyJY-20348-trigger-setup-DI-layout-on-team-creationJY-20326-refactor-info-message-in-commandJY-20317-fix-auto-log-delay-issue-on-all-channels-disabledJY-20312-remove-on-update-change-last-synced-at-crm-configurationsJY-20306-SF-skip-auto-sync-for-task-based-playbookJY-20192-remove-deleted-team-from-saved-search-filtersJY-20197-import-opportunity-batch-jobJY-20293-enable-status-field-for-pipedrive-dealsJY-20191-remove-commands-interactive-promptsJY-20118-change-default-sync-strategyJY-20183-add-cache-on-auto-log-delayJY-20197-add-import-opportunity-batch-job20118-hs-opportunity-make-webhook-strategy-defaultJY-20118-make-default-hs-opportunity-sync-strategy-webhook-basedJY-20196-handle-opportunity-without-noteJY-20118-improve-opportunity-importJY-20189-handle-activity-search-on-deleted-groupsJY-20160JY-20145-filter-out-converted-leads-when-matchingJY-20150-skip-push-summary-on-summary-ready-1f-autologJY-20132-fix-note-encodingJY-19792-clean-logslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20725-handle-HS-search-rate-limit) $ devroot@docker_lamp_1:/home/jiminny# ](ahl| Daily - Platform • in 30 mA100% C47 8• Mon 11 May 9:16:001881-zsh-zsh885screenpipe"0 ₴6DEV...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
NULL
|
15090
|
|
15117
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
PhostormFV faVsco.jsVIewINavicareCode%9 JY-20725-handle-HS-search-rate-limit-Keractorroledey© BatchSyncCollectore balchsynckealsse© HubspotSyncStrategyBase.phpCachedcrmservicebecorator.onp© SyncRelatedActivityManager.php© ProspectCache.phpo closeaDealstagess)MatchactivitycrmData.ong© CrmActivityService.phgDealrielasservice.g© CrmObiectsResolver.phpc)Decorateacuivilv.or© FieldDefinitions.phpC) FieldT vpeconverteclass sacent extends Baseulzent amplements hubspotelzentintertacepublic function deleteEngagement(string SengagementId): voide Hubspotclientinterc) Hubspotlokenman$this->getInstance() ->engagements()->delete((int) $engagementId);© PayloadBuilder.phpC) Remotecrmobiectr© ResponseNormalizec) Service,ono948 0public function getAssociationsData(array $ids, string $from0bject, string $to0bject): array© SyncFieldAction.phC) SvncRelatedActivitC) WebhookSvncBatclSassociationData = [];SidChunks = arnav chunk(Sids!length: self::ASSOCIATIONS_BATCH_SIZE_LIMIT);v O IntegrationApp> O Accessors• MAnConfigODTOFiltersJobsDProspectSearchStraforeach ($idChunks as $idChunk) {try{$batchInput = new \HubSpot\CLient\Crm\Associations\Model\BatchInputPublic0bjectId();$batchInput->setInputs(array_map(function ($id) {$publicObjectId = new \HubSpot\CLient\Crm\Associations\Model\Public0bjectId();soubuicudecclo>sectas10W service lralts© DataClient.phpreturn $public0bjectId;}, $idChunk)):A2 A64 X1 21 A L 15II 1 IMHM= 241 31MіH-ITConsole,LOg XChanges 12 files= env.local aonC) Client.oho aon/Services/Crm/Hubsooti© HandleHubspotRateLimit.php app/Jobs/Middleware© HubspotClientinterface.php app/Services/Crm/Hubspot© HubspotPaginationService.php app/Services/Crm/Hubspot/Pagination©JiminnyDebugCommand.php app/Console/Commandsphe logging.php config©MatchActivityCrmData.php app/Jobs/Crm© MatchCrmData.php app/Jobs/Activity/lmport© PaginationState.php app/Services/Crm/Hubspot/Pagination© RateLimitException.php app/Exceptions© Service.php app/Services/Crm/Hubspot~ Unversioned Files 9 files= env.nikilocal apoE.env.other app© CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/Repki tavicon.ico public= ids.txt appiaraw sol querv sall aool© SimulateWebhooksCommand.php app/Console/Commands/Crm/HubspotT + 0+ → Side-by-side viewer -8 35f036ac app/Services/Crm/Hubspot/Client.phgDo not ignoreHighight words -X 1 ?// Fallback toSmessace = strtolower(se->cetressadeoo:return str contains(Smessage..'401 unauthorized') |1'http 401') |1str contains(Smessage, 'status code 401') 11|(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));/*** Validates and refreshes the access token if needed before API requests.} StoAssociations)•} catch (\Exception $e) {Sthis->log->error('[Hubspotl Failed to fetch associations'. lE laravel.log# console [PKob.A console (EU]A SF jiminny@localhost]A console (STAGING]A HS_Jocal (jiminny@localhost]accept-encoding"],"access-control-allow-credentials": ["false"],"server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3)",cfr;desc=\"9f80deb8e7c6dc3a-IAD)""],"x-content-type-options": ["nosniff"],"x-nuDspor-correlac1on-1d:l "0ryeuzdu-or0o-/812-baba-oosl/ccbsees"Set-Cookie":["_cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],"керогс-10":"1enapolnus"."url":nccos:a.nel.cloudtlare.comredorcV4.S=NYALSVIPorymszorSUnxY24S0ZKh"max_age\":6048005"J,"NEL": ["{"success fraction":0.01."max ade".604800-""Server": ["cloudflare"]}}{"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab" ,"trace id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}Curront vorcion40Dally - Platorm• In 2/nU AskJiminnyReportActivityServiceTest~100% L2&• Mon 11 May 9:18:09CascadeO HubSpot Pagination+0 ..sull request #12057 from jiminny/JY-20819-increase-download-transctip-rate-Limit75 -20817-T1x-deleting-old-tracksbse8t38768 Mr20 17 Fredete #12 o1 toa Kiminy/JY-29662-remaxe-vord-boostget /Users/ukas/jiminny/app Log -onetine --all - app/Services/Crm/Hubspot/Pag4nation/HubspotPaginationServiCe.php 261 |56973040d6 3Y-29456 code review sugesen6de4385261 JY-19401 extract HS pagination logic to separated classesCommand git, grep, headO git -C /Users/lukas/jiminny/app branch --all | grep -j "ratel|match\|pagination)|crm" | head -20 2>&1Run se+ SkipAsk anything (2AL)+ <> CodeSAdaptive• 014 differencesreturn se-›getresponseo?->getstatuscode === 4017Smessage = strtolower ($e->getMessage());return str contains(Smessage.'401 unauthorized') 11str_contains($message,"http 401') |1str contains(Smessage."status code 401')(preg_match('/\b401\b/', $message) === 1 && str_contains($message, 'unauthorized'));/*** Validates and refreshes the access token if needed before API requests.StoAssociations).} catch (RateLimitException $e) {thnow So.WN Windsurf Teamcf?4 spaces...
|
PhpStorm
|
faVsco.js – Client.php
|
NULL
|
15117
|
|
15214
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
PhostormVIewINavicareCodeFV faVsco.js?9 JY-20725-handle-HS-search-rate-limitroledey© [EMAIL]© ProspectCache.phpC)DecorateActivitv.on© MatchactivityermData.png© CrmActivityService.phgC) FieldTvoeConverteHubsnotclientinten© CrmObiectsResolver.php© HubspotTokenMan© PayloadBuilder.phpC) RemoteCrmObiectiResponseNormalize© Service.php© SyncFieldAction.ph© SyncRelatedActivit© WebhookSyncBatcl• Ca IntegrationApp› Oa Accessorsclass Cllent extends Baseclient 1mpLements HubspotclientintertaceA2 A65 K1AV1public function makeRequest(strina Sendpoint. Smethod = 'GET'. Spavload = [l. 2strina SauervString = null)sresponse = schis->gerinstance-›gecculentr-›requescenapoinc. senapoinc,query scrino: squeryscrino} else {Sresponse = Sthis->getInstance@->getClient(->request(Smethod. Sendpoint. ["ason' => (spavload)WApI•• contioODTOw rilters745/1 "110""109"DJOOS• Prospecisearchstr> → ServiceTraitsC) Dataclient.oho© DecorateActivitv.phC)Loca|Search.ohv1)Loca SearchintertaC) RemoteSearch.onoSremaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'):Sinterval= $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"$body= ison decode(((strina) Sresponse->aetBodvO true):ItsaIlluminate\Support\Facades\Log::channel('custom_channel')->info('$max'. PHP_EOL • print_r($max,lI kIlluminate\Support \Facades\Log::channel('custom_channel')->info('$remaining' . PHP_EOL • print_r(SiTlluminate Sunnont Cacades loa: •channel("custom channel!)->info(icintenvall• PHP_EOL • print_r(Sin\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body' . PHP_EOL . print_r($bod\=ShelConcoleChanaes 12 filed= env.local aonC) Client.oho aon/Services/Crm/HubsootiTJ0 + → Side-by-side viewer •Do not ignore8 35f036ac app/Services/Crm/Hubspot/Client.phgSthis->setVersion(self::MIN_API_VERSION):Hiahliaht wordsy© HandleHubspotRateLimit.php app/Jobs/Middleware© HubspotClientinterface.php app/Services/Crm/Hubspot© HubspotPaginationService.php app/Services/Crm/Hubspot/Pagination@ JiminnyDebugCommand.php app/Console/Commandsphp logging.php config© MatchActivityCrmData.php app/Jobs/Crm© MatchCrmData.php app/Jobs/Activity/Import© PaginationState.php app/Services/Crm/Hubspot/Pagination© RateLimitException.php app/Exceptions© Service.php app/Services/Crm/HubspotUnversioned Files 9 filesououic tunction cetranmumaoiversiono: strinoreturn self::MIN APT VERSION:SlastRecordtdi= env.nikilocal apoE.env.other appC) CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnvReportResultCommand.php app/Console/Commands/Re* Athrows NealAniFycention* Athrows ErmSycentionki tavicon.ico publicEids.txt aprpublic function getOpportunityById(string $crmId, array $fields): arrayiaraw sol querv sall aoolSimaneebnkscommandpht a/m/Console/Commands/Crm/Hubspoolner Code will hoin INF to underctand vour Laravel ann code II Generate II Don't Show Anvmore (19 minutes aao)trySdeal = Sthis->getNewInstance->crm->deals->basicApi->qetById(Dally - Platrorm • In 1om100% S2• • Mon 11 May 9:27:40AskJiminnyReportActivityServiceTest v+0 ..= custom.loa XA SF (jiminny@localhost]4 HS_local (jiminny@localhost]# console [PKOb.# console leu)A console [STAGING]accept-encoding"],"access-control-allow-credentials":["false"]."server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",cfr;desc=|"9f80deb8e7c6dc3a-IAD\""],"x-content-type-options": ["nosniff"],"x-hubspot-correlation-id":("019e02d0-6fd8-7812-bdba-885b7ccb3ee3"].MMi9.У"ser-Lookle:ct.dm=sLurcaugxvrzksopacronzvyknzinubzavrabeccmoy-1//81050/5-1.0.207-May-26 14:51:15 GMT: domain=.hubapi.com;: Http0nly: Secure: SameSite=None"]."керогс-10":"1enapolnus"."url":nccos:a.nel.cloudtlare.comredorcv4?s=NYALsVIPorymszorsunxy24S0zk"max_age\":6048005"J,"NEL":["{"success fraction":0.01."max ade".604800-""Server":"cloudflare"l?,,"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab","trace id":"c7ab8365-903f-46d4-9403-0e5b551e3545"CascadeHubspot Rate Limit Re9. Matchcrmbata rate limiter move is logically correct but asymmetric with the quardMatchCrmData.oho:103-1131 SrateLimite->canMakeRequest (Sactivitv->oetcrmo))4$this->release(...)return;ScrmObjects = $crm0bjectsResolver->resolveFromCall(...):SrateLimiter→>incrementRequestCount(Sactivity->getCrm0));Movina increlestCount to after resolveFromCall is correct — oreviouslv it counted the attemot even if the call failed. However. resolveFrondall canmake multiple CRM API calls (email match + phone match + domain match). The rate limiter counts this whole resolver as 1 request. If a preventive rate limiter wereadded inside Client, the ProviderRateLimiter at the job level would count "1 request" while the client made 3 calls - so the two counters would diverge and thepreventive limiter would still be meaninaful independentlv.Rate Limit counter Interaction — vatchcrnbata vs Cllent-Side Preventive LimitThe question about how the ProviderRateLimiter would interact with a preventive client-side rate limit:Current flowMData):1. canMakeRequestlo checks the Laravel cache-oased counter + 1ob-level, coarse-arained, oer-cRM-contic2. resolveFromCall() makes 2-3 actual HubSpot API calls3. incremIt a prevent ve rate limit were added in Client (e.a, before searcho):Ask anything (&AL)+ <> CodeSAdaptiveQ differencesct »Curront vorcionreturn 10:public function getMinimumApiVersion@: strinareturn self::MIN APT VERSION:SlastRecordId* Execute a search request against HubSpot CRM objects with rate limiting.* Qparam string $objectType The object type ('deals','companies', 'contacts', 'calls')* @panam array<string, mixed> $payload The search payload with filters, sorts, properties, etc.* @return array The search response with 'results', 'total', 'paging' keys* Athrows RateLimitException When rate limit is hit+ Athnowe Hubeno+Gycention An APT ennonclWN Windsurf Teams724•60 UITF.8io 4 spaces...
|
PhpStorm
|
faVsco.js – Client.php
|
NULL
|
15214
|
|
15054
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
PhpStormFV faVsco.jsVIewINavicareCode%9 JY-20725-handle-HS-search-rate-limit-KeractorProletey© ImportTwilioVideosCoIsActivitykeaayrortmatchermbata.ongc UpoatecrmrielaDac) Upoatecustomerm?J Justcall> D PushSummaryToCrm> C RingCentral> D ZoomPhone© ActivityChangeCatego© AssignOwnership.phpc) ConterencecrmMatch©DeleteActivities.phpC) DeleteTeamchurndata© Delete TeamsRetentiorC) HardDeleteActivities.o©HardDeleteActivity.phy© MatchMeetingOwner.p©ReindexForAccountJol(c) RoindeysorContact.lot© ReindexForGroupJob.f© ReindexForLeadJob.pt© ReindexForOpportunit!© ReindexForUserJob.pr© RetryActivitySyncJob./© syncacuvity.onpolewalaWailewladialalh© HubspotSyncStrategyBase.phpy syneermenttes tralt.onpCachedcrmservicebecorator.onp© ProspectCache.php© CheckAndRetryRemoteMatch.php© MatchactivityermData.png© ermactivilyservice.phpMatchermbata.ono xclass Matchermbata 1mpLements ShouldoueueoUbLIerunction nandle a=| A7X2 A y 15return;if (! SrateLimiter->canMakeRequest(Sactivity->getCrm())) {$this->logMessage('Rate limit reached, retrying');$this-›release( delay: $rateLimiter-›requestAvailableIn($activity->getCrm()) + random_int(1, 60));Tecurlr$this->LogMessage('Resolving CRM objects');$crmObjects = $crmObjectsResolver->resolveFromCall($this->crmService, $this->call);SrateLimiter->incrementRequestCount($activity->getCrm());if Cempty($crmObjects)) {sth1s-> Loqhessage"Could not resolve cki obzects, retryinq')nSthis->release( delav: 3600):Console xLog xChanaes 12 filed=.env.local app© Client.php app/Services/Crm/Hubspot© HandleHubspotRateLimit.php app/Jobs/Middleware© HubspotClientinterface.php app/Services/Crm/Hubspot© HubspotPaginationService.php app/Services/Crm/Hubspot/Pagination©JiminnyDebugCommand.php app/Console/Commandsphe logging.php config©MatchActivityCrmData.php app/Jobs/Crm© MatchCrmData.php app/Jobs/Activity/lmport© PaginationState.php app/Services/Crm/Hubspot/Pagination© RateLimitException.php app/Exceptions© Service.php app/Services/Crm/HubspotUnversioned Files 9 filesE .env.nikilocal appE.env.other app© CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/Rep6 favicon.ico public= ids.txt appiaraw sol querv sall aoolosimuev ehookscon mand php rar/console/Comands/Crm/HubspotHelper Code will help IDE to understand your Laravel app code. // Generate // Don't Show Anymore (3 minutes ago)T + 0+ → Side-by-side viewer -Do not ignoreCurrent version tests/Unit/Policies/CanAccessAiReportsTest.php<?ohpHighlight words →X B?declare(strict types=1)namespace Tests Unit Policles:use JaminnvcontractsAcu.Permisszonenumuse Jiminny Models. Teamuse Jiminny\Models\User;use Jiminny Policies UserPolicv:use Jiminny|Repositories\AutomatedReportsRepository;use PlPlni+ Sramework Attrihutes DataProviden:use PHPUnit\Framework\Mock0bject\Mock0bject;use puPllni+ Enamewonk Tectrase:class CanAccessAiReportsTest extends TestCaseprivate AutomatedReportsRepository&Mock0bject $automatedReportsRepository;private UserPolicy $policy;laravel.log# console [PKob.A console (EU]A SF jiminny@localhost]A console (STAGING]A HS_Jocal (jiminny@localhost]accept-encoding"],w V19 ^V"access-control-allow-credentials": ["false"],"server-timing": ["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3)",cfr;desc=\"9f80deb8e7c6dc3a-IAD)""],"x-content-type-options": ["nosniff"],"x-hubspot-correlation-id" : ["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],"Set-Cookie":["_cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.107-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],"керогс-10":"1enapolnus"."url":nccos:a.nel.cloudtlare.comredorcV4.S=NYALSVIPorymszorSUnxY24S0ZKh"max_age\":6048005"J,"NEL": ["{"success fraction":0.01.\"report_tol":\"cf-nell","max ade".604800-""Server": ["cloudflare"]f}{"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab" ,"trace 1d"."c7ab8365-903f-46d4-9403-0e5b551e3545"CascadeNew CascadeSO lыo| Daily - Platform - in 34mAskJiminnyReportActivityServiceTest100%C4.•&• Mon 11 May 9:11:51e a t+0 ..Cascade Code * •.Kick oft a new oroiect. Make chancesacross vour entire codebase.© HubSpot CRM Call Review© Investigating Rate Limit Errors© HubSpot Rate Limit Reviewvbe dit. Se not oneses aitier and make a very ctre+ ‹› CodeSAdaptiveies. Wi Char break anyhing Ase lokn,on.pnp delient.onp @raginacionstate.pnpW Windsurf Teams 112:54 UTF-8 P 4 spaces...
|
PhpStorm
|
faVsco.js – MatchCrmData.php
|
NULL
|
15054
|