Skip to content

Commit 202d116

Browse files
committed
ACPT-1751: Enable Suspension of Cron-Triggered Indexer Operations
- Skip indexer reindex and view update if the specified indexer or any other indexer that shares its shared_index are suspended;
1 parent a684b70 commit 202d116

File tree

5 files changed

+97
-20
lines changed

5 files changed

+97
-20
lines changed

app/code/Magento/Indexer/Console/Command/IndexerSetStatusCommand.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
use Symfony\Component\Console\Output\OutputInterface;
2020

2121
/**
22-
* Command for setting index status for indexers
22+
* Command for setting index status for indexers.
2323
*/
2424
class IndexerSetStatusCommand extends AbstractIndexerManageCommand
2525
{
@@ -85,7 +85,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
8585
}
8686

8787
/**
88-
* Get list of arguments for the command
88+
* Gets list of arguments for the command.
8989
*
9090
* @return InputOption[]
9191
*/
@@ -102,7 +102,7 @@ public function getInputList(): array
102102
}
103103

104104
/**
105-
* Check if all CLI command options are provided
105+
* Checks if all CLI command options are provided.
106106
*
107107
* @param InputInterface $input
108108
* @return string[]
@@ -136,7 +136,7 @@ private function validate(InputInterface $input): array
136136
}
137137

138138
/**
139-
* Update the status of a specified indexer
139+
* Updates the status of a specified indexer.
140140
*
141141
* @param IndexerInterface $indexer
142142
* @param string $newStatus

app/code/Magento/Indexer/Model/Indexer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ public function isInvalid()
335335
}
336336

337337
/**
338-
* Check whether indexer is valid
338+
* Checks whether indexer is suspended.
339339
*
340340
* @return bool
341341
*/

app/code/Magento/Indexer/Model/Processor.php

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,16 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
7+
68
namespace Magento\Indexer\Model;
79

810
use Magento\Framework\App\ObjectManager;
911
use Magento\Framework\Indexer\ConfigInterface;
1012
use Magento\Framework\Indexer\IndexerInterface;
1113
use Magento\Framework\Indexer\IndexerInterfaceFactory;
14+
use Magento\Framework\Indexer\IndexerRegistry;
15+
use Magento\Framework\Indexer\StateInterface;
1216
use Magento\Framework\Mview\ProcessorInterface;
1317
use Magento\Indexer\Model\Processor\MakeSharedIndexValid;
1418

@@ -47,25 +51,33 @@ class Processor
4751
*/
4852
protected $makeSharedValid;
4953

54+
/**
55+
* @var IndexerRegistry
56+
*/
57+
private IndexerRegistry $indexerRegistry;
58+
5059
/**
5160
* @param ConfigInterface $config
5261
* @param IndexerInterfaceFactory $indexerFactory
5362
* @param Indexer\CollectionFactory $indexersFactory
5463
* @param ProcessorInterface $mviewProcessor
5564
* @param MakeSharedIndexValid|null $makeSharedValid
65+
* @param IndexerRegistry|null $indexerRegistry
5666
*/
5767
public function __construct(
5868
ConfigInterface $config,
5969
IndexerInterfaceFactory $indexerFactory,
6070
Indexer\CollectionFactory $indexersFactory,
6171
ProcessorInterface $mviewProcessor,
62-
?MakeSharedIndexValid $makeSharedValid = null
72+
?MakeSharedIndexValid $makeSharedValid = null,
73+
?IndexerRegistry $indexerRegistry = null
6374
) {
6475
$this->config = $config;
6576
$this->indexerFactory = $indexerFactory;
6677
$this->indexersFactory = $indexersFactory;
6778
$this->mviewProcessor = $mviewProcessor;
6879
$this->makeSharedValid = $makeSharedValid ?: ObjectManager::getInstance()->get(MakeSharedIndexValid::class);
80+
$this->indexerRegistry = $indexerRegistry ?: ObjectManager::getInstance()->get(IndexerRegistry::class);
6981
}
7082

7183
/**
@@ -81,7 +93,9 @@ public function reindexAllInvalid()
8193
$indexer->load($indexerId);
8294
$indexerConfig = $this->config->getIndexer($indexerId);
8395

84-
if ($indexer->isInvalid() && !$indexer->isSuspended()) {
96+
if ($indexer->isInvalid() && !$indexer->isSuspended()
97+
&& !$this->isSharedIndexSuspended($indexerConfig['shared_index'])
98+
) {
8599
// Skip indexers having shared index that was already complete
86100
$sharedIndex = $indexerConfig['shared_index'] ?? null;
87101
if (!in_array($sharedIndex, $this->sharedIndexesComplete)) {
@@ -97,6 +111,36 @@ public function reindexAllInvalid()
97111
}
98112
}
99113

114+
/**
115+
* Checks if any indexers within a group that share a common 'shared_index' ID are suspended.
116+
*
117+
* @param string|null $sharedIndexId
118+
* @return bool
119+
*/
120+
private function isSharedIndexSuspended(?string $sharedIndexId): bool
121+
{
122+
if ($sharedIndexId === null) {
123+
return false;
124+
}
125+
126+
$indexers = $this->config->getIndexers();
127+
128+
foreach ($indexers as $indexerId => $config) {
129+
// Check if the indexer shares the same 'shared_index'
130+
if (isset($config['shared_index']) && $config['shared_index'] === $sharedIndexId) {
131+
$indexer = $this->indexerRegistry->get($indexerId);
132+
133+
// If any indexer that shares the 'shared_index' is suspended, return true
134+
if ($indexer->getStatus() === StateInterface::STATUS_SUSPENDED) {
135+
return true;
136+
}
137+
}
138+
}
139+
140+
// If none of the shared indexers are suspended, return false
141+
return false;
142+
}
143+
100144
/**
101145
* Regenerate indexes for all indexers
102146
*

app/code/Magento/Indexer/Plugin/Mview/ViewUpdatePlugin.php

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use Psr\Log\LoggerInterface;
1515

1616
/**
17-
* Plugin to prevent updating a view if the associated indexer is suspended
17+
* Plugin to prevent view update if the associated indexer or any indexer sharing the same shared_index is suspended.
1818
*/
1919
class ViewUpdatePlugin
2020
{
@@ -49,34 +49,35 @@ public function __construct(
4949
}
5050

5151
/**
52-
* Prevent updating a view if the associated indexer is suspended
52+
* Skips updating the view if its associated indexer or any indexer with the same shared index is suspended.
5353
*
5454
* @param ViewInterface $subject
5555
* @param callable $proceed
5656
* @return void
5757
*/
5858
public function aroundUpdate(ViewInterface $subject, callable $proceed): void
5959
{
60-
$indexerId = $this->mapViewIdToIndexerId($subject->getId());
60+
$viewId = $subject->getId();
61+
$indexerId = $this->mapViewIdToIndexerId($viewId);
6162

6263
if ($indexerId === null) {
6364
$proceed();
6465
return;
6566
}
6667

67-
$indexer = $this->indexerRegistry->get($indexerId);
68-
69-
if ($indexer->getStatus() != StateInterface::STATUS_SUSPENDED) {
70-
$proceed();
71-
} else {
68+
// Check if the direct indexer or any related indexers via shared_index are suspended
69+
if ($this->isIndexerOrSharedIndexSuspended($indexerId)) {
7270
$this->logger->info(
73-
"Indexer {$indexer->getId()} is suspended. The view {$subject->getId()} will not be updated."
71+
"Suspended status detected for indexer {$indexerId} or its shared index. "
72+
. "Any potential update for view {$viewId} will be skipped regardless of backlog status.",
7473
);
74+
} else {
75+
$proceed();
7576
}
7677
}
7778

7879
/**
79-
* Map view ID to indexer ID
80+
* Maps a view ID to its corresponding indexer ID.
8081
*
8182
* @param string $viewId
8283
* @return string|null
@@ -90,4 +91,33 @@ private function mapViewIdToIndexerId(string $viewId): ?string
9091
}
9192
return null;
9293
}
94+
95+
/**
96+
* Determines if the specified indexer or any other indexer that shares its shared_index are suspended.
97+
*
98+
* @param string $indexerId
99+
* @return bool
100+
*/
101+
private function isIndexerOrSharedIndexSuspended(string $indexerId): bool
102+
{
103+
$indexer = $this->indexerRegistry->get($indexerId);
104+
if ($indexer->getStatus() === StateInterface::STATUS_SUSPENDED) {
105+
return true;
106+
}
107+
108+
// Retrieve the shared_index ID from the indexer's configuration
109+
$sharedIndexId = $this->indexerConfig->getIndexer($indexerId)['shared_index'] ?? null;
110+
if ($sharedIndexId !== null) {
111+
foreach ($this->indexerConfig->getIndexers() as $otherIndexerId => $config) {
112+
if (($config['shared_index'] ?? null) === $sharedIndexId) {
113+
$otherIndexer = $this->indexerRegistry->get($otherIndexerId);
114+
if ($otherIndexer->getStatus() === StateInterface::STATUS_SUSPENDED) {
115+
return true;
116+
}
117+
}
118+
}
119+
}
120+
121+
return false;
122+
}
93123
}

lib/internal/Magento/Framework/Indexer/SuspendableIndexerInterface.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@
88
namespace Magento\Framework\Indexer;
99

1010
/**
11-
* Interface for indexers that can be suspended
11+
* Interface for managing the suspended status of indexers.
12+
*
13+
* Allows for temporary suspension of indexer auto-updates by cron,
14+
* facilitating performance optimization during bulk operations.
1215
*/
1316
interface SuspendableIndexerInterface extends IndexerInterface
1417
{
1518
/**
16-
* Check whether indexer is suspended
19+
* Determines if the indexer is suspended.
1720
*
18-
* @return bool
21+
* @return bool True if suspended, false otherwise.
1922
*/
2023
public function isSuspended(): bool;
2124
}

0 commit comments

Comments
 (0)