Skip to content

Commit 2d2da26

Browse files
authored
Merge pull request #85 from craftcms/feature/user-package-retries
Use the built-in retry behavior in the API package
2 parents 828e0d7 + 49ac028 commit 2d2da26

File tree

11 files changed

+25
-165
lines changed

11 files changed

+25
-165
lines changed

CHANGELOG.md

+3-8
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,10 @@
22

33
## 4.0.0 - WIP
44
- Shopify now requires `shopify/shopify-api` 5.2.0 or later.
5-
- Shopify now requires custom apps to be created with event version set to `2023-10`.
6-
7-
## Unreleased
8-
9-
- Added an `async` flag to the `craft/shopify/sync` command.
10-
- Added an `async` param to the sync utility.
5+
- Shopify now the related custom app to be created with event version set to `2023-10`.
6+
- Syncing meta fields is no longer performed in a job.
7+
- Deprecated the `craft\shopify\jobs\UpdateProductMetadata` job.
118
- Fixed a bug where the template routing setting would not save.
12-
- Added `craft\shopify\helpers\Api`.
13-
- Added `craft\shopify\jobs\UpdateProductVariants`.
149

1510
## 3.2.0 - 2023-06-12
1611

src/console/controllers/SyncController.php

+7-18
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
use craft\console\Controller;
1111
use craft\helpers\Console;
12+
use craft\shopify\elements\Product;
1213
use craft\shopify\Plugin;
1314
use yii\console\ExitCode;
1415

@@ -23,22 +24,6 @@ class SyncController extends Controller
2324
/** @var string $defaultAction */
2425
public $defaultAction = 'products';
2526

26-
/**
27-
* @var bool Whether to sync product and other associated data in the queue.
28-
* @since 3.3.0
29-
*/
30-
public bool $async = true;
31-
32-
/**
33-
* @inheritdoc
34-
*/
35-
public function options($actionID): array
36-
{
37-
$options = parent::options($actionID);
38-
$options[] = 'async';
39-
return $options;
40-
}
41-
4227
/**
4328
* Sync all Shopify data.
4429
*/
@@ -60,7 +45,11 @@ public function actionProducts(): int
6045
private function _syncProducts(): void
6146
{
6247
$this->stdout('Syncing Shopify products…' . PHP_EOL . PHP_EOL, Console::FG_GREEN);
63-
Plugin::getInstance()->getProducts()->syncAllProducts($this->async);
64-
$this->stdout('Finished' . PHP_EOL . PHP_EOL, Console::FG_GREEN);
48+
// start timer
49+
$start = microtime(true);
50+
Plugin::getInstance()->getProducts()->syncAllProducts();
51+
// end timer
52+
$time = microtime(true) - $start;
53+
$this->stdout('Finished syncing ' . Product::find()->count() . ' product(s) in ' . round($time, 2) . 's' . PHP_EOL . PHP_EOL, Console::FG_GREEN);
6554
}
6655
}

src/controllers/ProductsController.php

+1-3
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,7 @@ public function actionProductIndex(): Response
4545
*/
4646
public function actionSync(): Response
4747
{
48-
$async = (bool)Craft::$app->getRequest()->getParam('async', false);
49-
50-
Plugin::getInstance()->getProducts()->syncAllProducts($async);
48+
Plugin::getInstance()->getProducts()->syncAllProducts();
5149
return $this->asSuccess(Craft::t('shopify', 'Products successfully synced'));
5250
}
5351

src/helpers/Api.php

-31
This file was deleted.

src/jobs/UpdateProductMetadata.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44

55
use craft\queue\BaseJob;
66
use craft\shopify\elements\Product;
7-
use craft\shopify\helpers\Api as ApiHelper;
87
use craft\shopify\helpers\Metafields as MetafieldsHelper;
98
use craft\shopify\Plugin;
109
use craft\shopify\records\ProductData as ProductDataRecord;
1110

1211
/**
1312
* Updates the metadata for a Shopify product.
13+
*
14+
* @deprecated 4.0.0 No longer used internally due to the use of `Retry-After` headers in the Shopify API.
1415
*/
1516
class UpdateProductMetadata extends BaseJob
1617
{
@@ -31,7 +32,6 @@ public function execute($queue): void
3132
$productData = ProductDataRecord::find()->where(['shopifyId' => $this->shopifyProductId])->one();
3233
$productData->metaFields = $metaFields;
3334
$productData->save();
34-
ApiHelper::rateLimit(); // Avoid rate limiting
3535
}
3636
}
3737

src/jobs/UpdateProductVariants.php

-47
This file was deleted.

src/models/Settings.php

-15
Original file line numberDiff line numberDiff line change
@@ -28,23 +28,10 @@ class Settings extends Model
2828
public string $template = '';
2929
private mixed $_productFieldLayout;
3030

31-
/**
32-
* @var bool Whether to rate limit requests to Shopify
33-
* @since 3.3.0
34-
*/
35-
public bool $rateLimitRequests = true;
36-
37-
/**
38-
* @var int The number of seconds to wait between requests
39-
* @since 3.3.0
40-
*/
41-
public int $rateLimitSeconds = 1;
42-
4331
public function rules(): array
4432
{
4533
return [
4634
[['apiSecretKey', 'apiKey', 'accessToken', 'hostName'], 'required'],
47-
[['rateLimitSeconds', 'rateLimitRequests'], 'safe'],
4835
];
4936
}
5037

@@ -60,8 +47,6 @@ public function attributeLabels(): array
6047
'hostName' => Craft::t('shopify', 'Shopify Host Name'),
6148
'uriFormat' => Craft::t('shopify', 'Product URI format'),
6249
'template' => Craft::t('shopify', 'Product Template'),
63-
'rateLimitRequests' => Craft::t('shopify', 'Rate Limit Requests'),
64-
'rateLimitSeconds' => Craft::t('shopify', 'Rate Limit Seconds'),
6550
];
6651
}
6752

src/services/Api.php

+6-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
use craft\base\Component;
1212
use craft\helpers\App;
1313
use craft\log\MonologTarget;
14-
use craft\shopify\helpers\Api as ApiHelper;
1514
use craft\shopify\Plugin;
1615
use Shopify\Auth\FileSessionStorage;
1716
use Shopify\Auth\Session;
@@ -92,15 +91,19 @@ public function getProductIdByInventoryItemId($id): ?int
9291
* Retrieves "metafields" for the provided Shopify product ID.
9392
*
9493
* @param int $id Shopify Product ID
94+
* @return ShopifyMetafield[]
9595
*/
9696
public function getMetafieldsByProductId(int $id): array
9797
{
98-
return $this->getAll(ShopifyMetafield::class, [
98+
/** @var ShopifyMetafield[] $metafields */
99+
$metafields = $this->getAll(ShopifyMetafield::class, [
99100
'metafield' => [
100101
'owner_id' => $id,
101102
'owner_resource' => 'product',
102103
],
103104
]);
105+
106+
return $metafields;
104107
}
105108

106109
/**
@@ -147,7 +150,6 @@ public function getAll(string $type, array $params = []): array
147150
[],
148151
$type::$NEXT_PAGE_QUERY ?: $params,
149152
));
150-
ApiHelper::rateLimit(); // Avoid rate limiting
151153
} while ($type::$NEXT_PAGE_QUERY);
152154

153155
return $resources;
@@ -196,7 +198,7 @@ public function getSession(): ?Session
196198
sessionStorage: new FileSessionStorage(Craft::$app->getPath()->getStoragePath() . DIRECTORY_SEPARATOR . 'shopify_api_sessions'),
197199
apiVersion: self::SHOPIFY_API_VERSION,
198200
isEmbeddedApp: false,
199-
logger: $webLogTarget->getLogger()
201+
logger: $webLogTarget->getLogger(),
200202
);
201203

202204
$hostName = App::parseEnv($pluginSettings->hostName);

src/services/Products.php

+6-26
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@
1111
use craft\shopify\elements\Product;
1212
use craft\shopify\elements\Product as ProductElement;
1313
use craft\shopify\events\ShopifyProductSyncEvent;
14-
use craft\shopify\helpers\Api as ApiHelper;
1514
use craft\shopify\helpers\Metafields as MetafieldsHelper;
16-
use craft\shopify\jobs\UpdateProductMetadata;
17-
use craft\shopify\jobs\UpdateProductVariants;
1815
use craft\shopify\Plugin;
1916
use craft\shopify\records\ProductData as ProductDataRecord;
2017
use Shopify\Rest\Admin2023_10\Metafield as ShopifyMetafield;
@@ -61,32 +58,15 @@ class Products extends Component
6158
* @throws \Throwable
6259
* @throws \yii\base\InvalidConfigException
6360
*/
64-
public function syncAllProducts(bool $asynchronous = true): void
61+
public function syncAllProducts(): void
6562
{
6663
$api = Plugin::getInstance()->getApi();
6764
$products = $api->getAllProducts();
6865

6966
foreach ($products as $product) {
70-
if ($asynchronous) {
71-
$this->createOrUpdateProduct($product);
72-
Craft::$app->getQueue()->push(new UpdateProductMetadata([
73-
'description' => Craft::t('shopify', 'Updating product metafields for “{title}”', [
74-
'title' => $product->title,
75-
]),
76-
'shopifyProductId' => $product->id,
77-
]));
78-
Craft::$app->getQueue()->push(new UpdateProductVariants([
79-
'description' => Craft::t('shopify', 'Updating product variants for “{title}”', [
80-
'title' => $product->title,
81-
]),
82-
'shopifyProductId' => $product->id,
83-
]));
84-
} else {
85-
$metaFields = $api->getMetafieldsByProductId($product->id);
86-
ApiHelper::rateLimit();
87-
$variants = $api->getVariantsByProductId($product->id);
88-
$this->createOrUpdateProduct($product, $metaFields, $variants);
89-
}
67+
$variants = $api->getVariantsByProductId($product->id);
68+
$metafields = $api->getMetafieldsByProductId($product->id);
69+
$this->createOrUpdateProduct($product, $metafields, $variants);
9070
}
9171

9272
// Remove any products that are no longer in Shopify just in case.
@@ -126,7 +106,8 @@ public function syncProductByInventoryItemId($id): void
126106
if ($productId = $api->getProductIdByInventoryItemId($id)) {
127107
$product = $api->getProductByShopifyId($productId);
128108
$metaFields = $api->getMetafieldsByProductId($product->id);
129-
$this->createOrUpdateProduct($product, $metaFields);
109+
$variants = $api->getVariantsByProductId($product->id);
110+
$this->createOrUpdateProduct($product, $metaFields, $variants);
130111
}
131112
}
132113

@@ -161,7 +142,6 @@ public function createOrUpdateProduct(ShopifyProduct $product, array $metafields
161142
'updatedAt' => $product->updated_at,
162143
'variants' => $variants ?? $product->variants,
163144
'vendor' => $product->vendor,
164-
// This one is unusual, because we’re merging two different Shopify API resources:
165145
'metaFields' => $metaFields,
166146
];
167147

src/templates/utilities/_sync.twig

-9
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,6 @@
55
{{ actionInput('') }}
66
{{ csrfInput() }}
77

8-
{{ forms.lightswitchField({
9-
label: "Use queue for syncing related objects like meta fields."|t('shopify'),
10-
warning: 'If disabled timeouts may occur, or API rate limits may be hit.'|t('commerce'),
11-
id: 'async',
12-
name: 'async',
13-
value: 1,
14-
on: true
15-
}) }}
16-
178
<a class="btn submit formsubmit" data-icon="refresh"
189
data-action="shopify/products/sync"
1910
data-confirm="{{ 'Are you sure you want run a complete sync of all products?'|t('shopify') }}">

src/translations/en/shopify.php

-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616
return [
1717
'Product Template' => 'Product Template',
1818
'Product URI format' => 'Product URI format',
19-
'Rate Limit Requests' => 'Rate Limit Requests',
20-
'Rate Limit Seconds' => 'Rate Limit Seconds',
2119
'Shopify API Key' => 'Shopify API Key',
2220
'Shopify API Secret Key' => 'Shopify API Secret Key',
2321
'Shopify Access Token' => 'Shopify Access Token',

0 commit comments

Comments
 (0)