Skip to content

Commit 1244b32

Browse files
committed
magento-engcom/bulk-api#4 Support for Async operations in WebAPI
- Reduced coupling between objects
1 parent 4b0935b commit 1244b32

File tree

4 files changed

+309
-227
lines changed

4 files changed

+309
-227
lines changed

app/code/Magento/AsynchronousOperations/Model/MassConsumer.php

Lines changed: 21 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -10,50 +10,28 @@
1010

1111
use Magento\Framework\App\ResourceConnection;
1212
use Psr\Log\LoggerInterface;
13-
use Magento\Framework\Exception\LocalizedException;
14-
use Magento\Framework\Exception\TemporaryStateExceptionInterface;
15-
use Magento\Framework\DB\Adapter\ConnectionException;
16-
use Magento\Framework\DB\Adapter\DeadlockException;
17-
use Magento\Framework\DB\Adapter\LockWaitException;
1813
use Magento\Framework\MessageQueue\MessageLockException;
1914
use Magento\Framework\MessageQueue\ConnectionLostException;
2015
use Magento\Framework\Exception\NotFoundException;
21-
use Magento\Framework\Exception\NoSuchEntityException;
2216
use Magento\Framework\MessageQueue\CallbackInvoker;
23-
use Magento\Framework\MessageQueue\MessageValidator;
24-
use Magento\Framework\MessageQueue\MessageEncoder;
2517
use Magento\Framework\MessageQueue\ConsumerConfigurationInterface;
2618
use Magento\Framework\MessageQueue\EnvelopeInterface;
2719
use Magento\Framework\MessageQueue\QueueInterface;
2820
use Magento\Framework\MessageQueue\LockInterface;
2921
use Magento\Framework\MessageQueue\MessageController;
3022
use Magento\Framework\MessageQueue\ConsumerInterface;
31-
use Magento\Framework\Serialize\Serializer\Json;
32-
use Magento\AsynchronousOperations\Api\Data\OperationInterface;
33-
use Magento\Framework\Bulk\OperationManagementInterface;
34-
use Magento\AsynchronousOperations\Model\ConfigInterface as AsyncConfig;
23+
use Magento\AsynchronousOperations\Model\OperationProcessorFactory;
3524

3625
/**
3726
* Class Consumer used to process OperationInterface messages.
3827
*/
3928
class MassConsumer implements ConsumerInterface
4029
{
41-
4230
/**
4331
* @var \Magento\Framework\MessageQueue\CallbackInvoker
4432
*/
4533
private $invoker;
4634

47-
/**
48-
* @var \Magento\Framework\MessageQueue\MessageEncoder
49-
*/
50-
private $messageEncoder;
51-
52-
/**
53-
* @var \Magento\Framework\MessageQueue\MessageValidator
54-
*/
55-
private $messageValidator;
56-
5735
/**
5836
* @var \Magento\Framework\App\ResourceConnection
5937
*/
@@ -64,16 +42,6 @@ class MassConsumer implements ConsumerInterface
6442
*/
6543
private $configuration;
6644

67-
/**
68-
* @var \Magento\Framework\Serialize\Serializer\Json
69-
*/
70-
private $jsonHelper;
71-
72-
/**
73-
* @var \Magento\Framework\Bulk\OperationManagementInterface
74-
*/
75-
private $operationManagement;
76-
7745
/**
7846
* @var \Magento\Framework\MessageQueue\MessageController
7947
*/
@@ -84,39 +52,37 @@ class MassConsumer implements ConsumerInterface
8452
*/
8553
private $logger;
8654

55+
/**
56+
* @var OperationProcessor
57+
*/
58+
private $operationProcessor;
59+
8760
/**
8861
* Initialize dependencies.
8962
*
90-
* @param \Magento\Framework\MessageQueue\CallbackInvoker $invoker
91-
* @param \Magento\Framework\MessageQueue\MessageValidator $messageValidator
92-
* @param \Magento\Framework\MessageQueue\MessageEncoder $messageEncoder
93-
* @param \Magento\Framework\App\ResourceConnection $resource
94-
* @param \Magento\Framework\MessageQueue\ConsumerConfigurationInterface $configuration
95-
* @param \Magento\Framework\Serialize\Serializer\Json $jsonHelper
96-
* @param \Magento\Framework\Bulk\OperationManagementInterface $operationManagement
97-
* @param \Magento\Framework\MessageQueue\MessageController $messageController
98-
* @param \Psr\Log\LoggerInterface|null $logger
63+
* @param CallbackInvoker $invoker
64+
* @param ResourceConnection $resource
65+
* @param MessageController $messageController
66+
* @param ConsumerConfigurationInterface $configuration
67+
* @param OperationProcessorFactory $operationProcessorFactory
68+
* @param LoggerInterface $logger
9969
*/
10070
public function __construct(
10171
CallbackInvoker $invoker,
102-
MessageValidator $messageValidator,
103-
MessageEncoder $messageEncoder,
10472
ResourceConnection $resource,
105-
ConsumerConfigurationInterface $configuration,
106-
Json $jsonHelper,
107-
OperationManagementInterface $operationManagement,
10873
MessageController $messageController,
109-
LoggerInterface $logger = null
74+
ConsumerConfigurationInterface $configuration,
75+
OperationProcessorFactory $operationProcessorFactory,
76+
LoggerInterface $logger
11077
) {
11178
$this->invoker = $invoker;
112-
$this->messageValidator = $messageValidator;
113-
$this->messageEncoder = $messageEncoder;
11479
$this->resource = $resource;
115-
$this->configuration = $configuration;
116-
$this->jsonHelper = $jsonHelper;
117-
$this->operationManagement = $operationManagement;
11880
$this->messageController = $messageController;
119-
$this->logger = $logger ? : \Magento\Framework\App\ObjectManager::getInstance()->get(LoggerInterface::class);
81+
$this->configuration = $configuration;
82+
$this->operationProcessor = $operationProcessorFactory->create([
83+
'configuration' => $configuration
84+
]);
85+
$this->logger = $logger;
12086
}
12187

12288
/**
@@ -150,12 +116,11 @@ private function getTransactionCallback(QueueInterface $queue)
150116

151117
$allowedTopics = $this->configuration->getTopicNames();
152118
if (in_array($topicName, $allowedTopics)) {
153-
$this->dispatchMessage($message);
119+
$this->operationProcessor->process($message->getBody());
154120
} else {
155121
$queue->reject($message);
156122
return;
157123
}
158-
159124
$queue->acknowledge($message);
160125
} catch (MessageLockException $exception) {
161126
$queue->acknowledge($message);
@@ -176,105 +141,4 @@ private function getTransactionCallback(QueueInterface $queue)
176141
}
177142
};
178143
}
179-
180-
/**
181-
* Decode OperationInterface message and process them.
182-
* Invokes service contract handler with the input params.
183-
* Updates the status of the mass operation.
184-
*
185-
* @param EnvelopeInterface $message
186-
* @throws LocalizedException
187-
*/
188-
private function dispatchMessage(EnvelopeInterface $message)
189-
{
190-
$operation = $this->messageEncoder->decode(AsyncConfig::SYSTEM_TOPIC_NAME, $message->getBody());
191-
$this->messageValidator->validate(AsyncConfig::SYSTEM_TOPIC_NAME, $operation);
192-
193-
$status = OperationInterface::STATUS_TYPE_COMPLETE;
194-
$errorCode = null;
195-
$messages = [];
196-
$topicName = $operation->getTopicName();
197-
$handlers = $this->configuration->getHandlers($topicName);
198-
try {
199-
$data = $this->jsonHelper->unserialize($operation->getSerializedData());
200-
$entityParams = $this->messageEncoder->decode($topicName, $data['meta_information']);
201-
$this->messageValidator->validate($topicName, $entityParams);
202-
} catch (\Exception $e) {
203-
$this->logger->error($e->getMessage());
204-
$status = OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED;
205-
$errorCode = $e->getCode();
206-
$messages[] = $e->getMessage();
207-
}
208-
209-
if ($errorCode === null) {
210-
foreach ($handlers as $callback) {
211-
$result = $this->executeHandler($callback, $entityParams);
212-
$status = $result['status'];
213-
$errorCode = $result['error_code'];
214-
$messages = array_merge($messages, $result['messages']);
215-
}
216-
}
217-
218-
$serializedData = (isset($errorCode)) ? $operation->getSerializedData() : null;
219-
$this->operationManagement->changeOperationStatus(
220-
$operation->getId(),
221-
$status,
222-
$errorCode,
223-
implode('; ', $messages),
224-
$serializedData
225-
);
226-
}
227-
228-
/**
229-
* Execute topic handler
230-
*
231-
* @param $callback
232-
* @param $entityParams
233-
* @return array
234-
*/
235-
private function executeHandler($callback, $entityParams)
236-
{
237-
$result = [
238-
'status' => OperationInterface::STATUS_TYPE_COMPLETE,
239-
'error_code' => null,
240-
'messages' => []
241-
];
242-
try {
243-
call_user_func_array($callback, $entityParams);
244-
$messages[] = sprintf('Service execution success %s::%s', get_class($callback[0]), $callback[1]);
245-
} catch (\Zend_Db_Adapter_Exception $e) {
246-
$this->logger->critical($e->getMessage());
247-
if ($e instanceof LockWaitException
248-
|| $e instanceof DeadlockException
249-
|| $e instanceof ConnectionException
250-
) {
251-
$result['status'] = OperationInterface::STATUS_TYPE_RETRIABLY_FAILED;
252-
$result['error_code'] = $e->getCode();
253-
$result['messages'][] = __($e->getMessage());
254-
} else {
255-
$result['status'] = OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED;
256-
$result['error_code'] = $e->getCode();
257-
$result['messages'][] =
258-
__('Sorry, something went wrong during product prices update. Please see log for details.');
259-
}
260-
} catch (NoSuchEntityException $e) {
261-
$this->logger->error($e->getMessage());
262-
$result['status'] = ($e instanceof TemporaryStateExceptionInterface) ?
263-
OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED :
264-
OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED;
265-
$result['error_code'] = $e->getCode();
266-
$result['messages'][] = $e->getMessage();
267-
} catch (LocalizedException $e) {
268-
$this->logger->error($e->getMessage());
269-
$result['status'] = OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED;
270-
$result['error_code'] = $e->getCode();
271-
$result['messages'][] = $e->getMessage();
272-
} catch (\Exception $e) {
273-
$this->logger->error($e->getMessage());
274-
$result['status'] = OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED;
275-
$result['error_code'] = $e->getCode();
276-
$result['messages'][] = $e->getMessage();
277-
}
278-
return $result;
279-
}
280144
}

app/code/Magento/AsynchronousOperations/Model/MassSchedule.php

Lines changed: 11 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -8,49 +8,27 @@
88

99
namespace Magento\AsynchronousOperations\Model;
1010

11-
use Magento\AsynchronousOperations\Api\Data\OperationInterface;
12-
use Magento\AsynchronousOperations\Api\Data\OperationInterfaceFactory;
1311
use Magento\Framework\DataObject\IdentityGeneratorInterface;
14-
use Magento\Framework\EntityManager\EntityManager;
1512
use Magento\Framework\Exception\LocalizedException;
1613
use Magento\AsynchronousOperations\Api\Data\ItemStatusInterfaceFactory;
1714
use Magento\AsynchronousOperations\Api\Data\AsyncResponseInterface;
1815
use Magento\AsynchronousOperations\Api\Data\AsyncResponseInterfaceFactory;
1916
use Magento\AsynchronousOperations\Api\Data\ItemStatusInterface;
20-
use Magento\Framework\MessageQueue\MessageValidator;
21-
use Magento\Framework\MessageQueue\MessageEncoder;
2217
use Magento\Framework\Bulk\BulkManagementInterface;
23-
use Magento\Framework\Serialize\Serializer\Json;
2418
use Magento\Framework\Exception\BulkException;
2519
use Psr\Log\LoggerInterface;
20+
use Magento\AsynchronousOperations\Model\ResourceModel\Operation\OperationRepository;
2621

2722
/**
2823
* Class MassSchedule used for adding multiple entities as Operations to Bulk Management with the status tracking
29-
*
30-
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
3124
*/
3225
class MassSchedule
3326
{
34-
/**
35-
* @var \Magento\AsynchronousOperations\Api\Data\OperationInterfaceFactory
36-
*/
37-
private $operationFactory;
38-
3927
/**
4028
* @var \Magento\Framework\DataObject\IdentityGeneratorInterface
4129
*/
4230
private $identityService;
4331

44-
/**
45-
* @var Json
46-
*/
47-
private $jsonSerializer;
48-
49-
/**
50-
* @var EntityManager
51-
*/
52-
private $entityManager;
53-
5432
/**
5533
* @var AsyncResponseInterfaceFactory
5634
*/
@@ -61,16 +39,6 @@ class MassSchedule
6139
*/
6240
private $itemStatusInterfaceFactory;
6341

64-
/**
65-
* @var MessageEncoder
66-
*/
67-
private $messageEncoder;
68-
69-
/**
70-
* @var MessageValidator
71-
*/
72-
private $messageValidator;
73-
7442
/**
7543
* @var \Magento\Framework\Bulk\BulkManagementInterface
7644
*/
@@ -81,43 +49,35 @@ class MassSchedule
8149
*/
8250
private $logger;
8351

52+
/**
53+
* @var OperationRepository
54+
*/
55+
private $operationRepository;
56+
8457
/**
8558
* Initialize dependencies.
8659
*
87-
* @param OperationInterfaceFactory $operationFactory
8860
* @param IdentityGeneratorInterface $identityService
89-
* @param Json $jsonSerializer
90-
* @param EntityManager $entityManager
9161
* @param ItemStatusInterfaceFactory $itemStatusInterfaceFactory
9262
* @param AsyncResponseInterfaceFactory $asyncResponseFactory
93-
* @param MessageEncoder $messageEncoder
94-
* @param MessageValidator $messageValidator
9563
* @param BulkManagementInterface $bulkManagement
9664
* @param LoggerInterface $logger
97-
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
65+
* @param OperationRepository $operationRepository
9866
*/
9967
public function __construct(
100-
OperationInterfaceFactory $operationFactory,
10168
IdentityGeneratorInterface $identityService,
102-
Json $jsonSerializer,
103-
EntityManager $entityManager,
10469
ItemStatusInterfaceFactory $itemStatusInterfaceFactory,
10570
AsyncResponseInterfaceFactory $asyncResponseFactory,
106-
MessageEncoder $messageEncoder,
107-
MessageValidator $messageValidator,
10871
BulkManagementInterface $bulkManagement,
109-
LoggerInterface $logger
72+
LoggerInterface $logger,
73+
OperationRepository $operationRepository
11074
) {
111-
$this->operationFactory = $operationFactory;
11275
$this->identityService = $identityService;
113-
$this->jsonSerializer = $jsonSerializer;
114-
$this->entityManager = $entityManager;
11576
$this->itemStatusInterfaceFactory = $itemStatusInterfaceFactory;
11677
$this->asyncResponseFactory = $asyncResponseFactory;
117-
$this->messageEncoder = $messageEncoder;
118-
$this->messageValidator = $messageValidator;
11978
$this->bulkManagement = $bulkManagement;
12079
$this->logger = $logger;
80+
$this->operationRepository = $operationRepository;
12181
}
12282

12383
/**
@@ -154,26 +114,7 @@ public function publishMass($topicName, array $entitiesArray, $groupId = null, $
154114
$requestItem = $this->itemStatusInterfaceFactory->create();
155115

156116
try {
157-
$this->messageValidator->validate($topicName, $entityParams);
158-
$encodedMessage = $this->messageEncoder->encode($topicName, $entityParams);
159-
160-
$serializedData = [
161-
'entity_id' => null,
162-
'entity_link' => '',
163-
'meta_information' => $encodedMessage,
164-
];
165-
$data = [
166-
'data' => [
167-
OperationInterface::BULK_ID => $groupId,
168-
OperationInterface::TOPIC_NAME => $topicName,
169-
OperationInterface::SERIALIZED_DATA => $this->jsonSerializer->serialize($serializedData),
170-
OperationInterface::STATUS => OperationInterface::STATUS_TYPE_OPEN,
171-
],
172-
];
173-
174-
/** @var \Magento\AsynchronousOperations\Api\Data\OperationInterface $operation */
175-
$operation = $this->operationFactory->create($data);
176-
$operations[] = $this->entityManager->save($operation);
117+
$operations[] = $this->operationRepository->createByTopic($topicName, $entityParams, $groupId);
177118
$requestItem->setId($key);
178119
$requestItem->setStatus(ItemStatusInterface::STATUS_ACCEPTED);
179120
$requestItems[] = $requestItem;

0 commit comments

Comments
 (0)