From 84c33c00efcb9d3653c1d1867c4778b3471fd0ea Mon Sep 17 00:00:00 2001 From: Stephen Callender Date: Tue, 5 May 2026 19:32:33 -0400 Subject: [PATCH] Prevent Klaviyo API connection issues from blocking requests --- CHANGELOG.md | 7 +++++++ composer.json | 2 +- src/Plugin.php | 25 +++++++++++++++++++---- src/controllers/ApiController.php | 34 ++++++++++++++++++++++++------- src/services/Api.php | 9 +++++++- 5 files changed, 64 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3b3c17..7123e18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Release Notes for KlaviyoConnect +## 7.2.4 - 2026-05-05 + +### Fixed + +- Klaviyo API failures no longer break host requests. Errors are caught, logged to the `klaviyoconnect` category, and the request continues. +- Klaviyo API calls now hard-cap at 5s (5s connect) with retries disabled, so an unresponsive Klaviyo can't stall the host request. + ### 7.2.3 - 2025-06-21 ### Fixed diff --git a/composer.json b/composer.json index bfafbb4..8e13375 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "Craft Commerce", "license": "proprietary", "type": "craft-plugin", - "version": "7.2.3", + "version": "7.2.4", "keywords": [ "klaviyo" ], diff --git a/src/Plugin.php b/src/Plugin.php index 69d4737..06f1dc7 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -20,6 +20,7 @@ use fostercommerce\klaviyoconnect\queue\jobs\TrackOrderComplete; use fostercommerce\klaviyoconnect\utilities\KCUtilities; use fostercommerce\klaviyoconnect\variables\Variable; +use Throwable; use yii\base\Event; /** @@ -71,14 +72,22 @@ static function (RegisterUrlRulesEvent $event): void { if ($settings->trackSaveUser) { Event::on(User::class, User::EVENT_AFTER_SAVE, static function (Event $event): void { - self::getInstance()->track->onSaveUser($event); + try { + self::getInstance()->track->onSaveUser($event); + } catch (Throwable $throwable) { + Craft::error('Klaviyo onSaveUser failed: ' . $throwable->getMessage(), 'klaviyoconnect'); + } }); } if (Craft::$app->plugins->isPluginEnabled('commerce')) { if ($settings->trackCommerceCartUpdated) { Event::on(Order::class, Order::EVENT_AFTER_SAVE, static function (Event $e): void { - self::getInstance()->track->onCartUpdated($e); + try { + self::getInstance()->track->onCartUpdated($e); + } catch (Throwable $throwable) { + Craft::error('Klaviyo onCartUpdated failed: ' . $throwable->getMessage(), 'klaviyoconnect'); + } }); } @@ -98,7 +107,11 @@ static function (RegisterUrlRulesEvent $event): void { OrderHistories::class, OrderHistories::EVENT_ORDER_STATUS_CHANGE, static function (OrderStatusEvent $e): void { - self::getInstance()->track->onStatusChanged($e); + try { + self::getInstance()->track->onStatusChanged($e); + } catch (Throwable $throwable) { + Craft::error('Klaviyo onStatusChanged failed: ' . $throwable->getMessage(), 'klaviyoconnect'); + } } ); } @@ -108,7 +121,11 @@ static function (OrderStatusEvent $e): void { Payments::class, Payments::EVENT_AFTER_REFUND_TRANSACTION, static function (RefundTransactionEvent $e): void { - self::getInstance()->track->onOrderRefunded($e); + try { + self::getInstance()->track->onOrderRefunded($e); + } catch (Throwable $throwable) { + Craft::error('Klaviyo onOrderRefunded failed: ' . $throwable->getMessage(), 'klaviyoconnect'); + } } ); } diff --git a/src/controllers/ApiController.php b/src/controllers/ApiController.php index 2120446..d9c7edc 100644 --- a/src/controllers/ApiController.php +++ b/src/controllers/ApiController.php @@ -9,7 +9,7 @@ use fostercommerce\klaviyoconnect\models\EventProperties; use fostercommerce\klaviyoconnect\Plugin; use fostercommerce\klaviyoconnect\queue\jobs\SyncOrders; -use GuzzleHttp\Exception\RequestException; +use Throwable; use yii\web\NotFoundHttpException; use yii\web\Response as YiiResponse; @@ -29,9 +29,23 @@ public function actionTrack(): mixed { $this->requirePostRequest(); - $this->identify(); - $this->trackEvent(); - $this->addProfileToLists(); + try { + $this->identify(); + } catch (Throwable $throwable) { + Craft::error('Klaviyo identify failed: ' . $throwable->getMessage(), 'klaviyoconnect'); + } + + try { + $this->trackEvent(); + } catch (Throwable $throwable) { + Craft::error('Klaviyo trackEvent failed: ' . $throwable->getMessage(), 'klaviyoconnect'); + } + + try { + $this->addProfileToLists(); + } catch (Throwable $throwable) { + Craft::error('Klaviyo addProfileToLists failed: ' . $throwable->getMessage(), 'klaviyoconnect'); + } $request = Craft::$app->getRequest(); if ($request->isAjax && ! $request->getParam('forward')) { @@ -76,7 +90,12 @@ public function actionSyncOrders(): void */ public function actionIdentify(): void { - $this->identify(); + try { + $this->identify(); + } catch (Throwable $throwable) { + Craft::error('Klaviyo identify failed: ' . $throwable->getMessage(), 'klaviyoconnect'); + } + $this->forwardOrRedirect(); } @@ -169,8 +188,9 @@ private function identify(): void $profile = $this->mapProfile(); try { Plugin::getInstance()->track->identifyUser($profile); - } catch (RequestException) { - // Swallow. Klaviyo responds with a 200. + } catch (Throwable $throwable) { + // Swallow. Klaviyo flake/outage must not break host request flow. + Craft::error('Klaviyo identifyUser failed: ' . $throwable->getMessage(), 'klaviyoconnect'); } } diff --git a/src/services/Api.php b/src/services/Api.php index a1997cd..44c7f8f 100644 --- a/src/services/Api.php +++ b/src/services/Api.php @@ -23,7 +23,14 @@ public function init(): void { parent::init(); - $this->api = new KlaviyoAPI($this->getSetting('klaviyoApiKey')); + $this->api = new KlaviyoAPI( + $this->getSetting('klaviyoApiKey'), + num_retries: 0, + guzzle_options: [ + 'connect_timeout' => 5, + 'timeout' => 5, + ], + ); } public function track(string $event, array $profile, ?EventProperties $eventProperties = null, ?string $timestamp = null): void