Skip to content

Commit ced77fc

Browse files
authored
[Improvement]: Improve processing of generic data index queue (#344)
* Improved index queue processing * Added migration * Apply php-cs-fixer changes * Async adding items for update/add operation * Apply php-cs-fixer changes * Removed auto-generated stub * Apply php-cs-fixer changes * Improved sql statements, avoided bc break * Added message to transport, improved reading values from sql result * Apply php-cs-fixer changes * Reverted changes to generateSelectQuery * Apply php-cs-fixer changes * Add processing of messages to tests * Using consume method * Revert "Using consume method" This reverts commit 139a547. * Revert "Add processing of messages to tests" This reverts commit 9dd4285. * Implemented SynchronousProcessingRelatedIdsService * Apply php-cs-fixer changes * Refactor deleteQueueEntries * Apply php-cs-fixer changes * Added documentation * Added upgrade note * Changing runners for codeception tests * Reverting to default runners * Adapted installer to create new table layout * Apply php-cs-fixer changes * Cast id to string for compatibility with lower versions --------- Co-authored-by: mcop1 <[email protected]>
1 parent d585b01 commit ced77fc

24 files changed

+615
-59
lines changed

config/pimcore/messenger.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ framework:
1212
Pimcore\Bundle\GenericDataIndexBundle\Message\DispatchQueueMessagesMessage: pimcore_generic_data_index_queue
1313
Pimcore\Bundle\GenericDataIndexBundle\Message\UpdateLanguageSettingsMessage: pimcore_generic_data_index_queue
1414
Pimcore\Bundle\GenericDataIndexBundle\Message\UpdateClassMappingMessage: pimcore_generic_data_index_queue
15+
Pimcore\Bundle\GenericDataIndexBundle\Message\EnqueueRelatedIdsMessage: pimcore_generic_data_index_queue
1516
buses:
1617
messenger.bus.pimcore-generic-data-index:
1718
middleware:

config/services/search/index.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ services:
2424
Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueue\SynchronousProcessingServiceInterface:
2525
class: Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueue\SynchronousProcessingService
2626

27+
Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueue\SynchronousProcessingRelatedIdsServiceInterface:
28+
class: Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueue\SynchronousProcessingRelatedIdsService
29+
2730
Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueue\EnqueueServiceInterface:
2831
class: Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueue\EnqueueService
2932

doc/01_Installation/02_Upgrade.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
Following steps are necessary during updating to newer versions.
44

55
## Upgrade to 2.2.0
6-
- Added `trackTotalHits` parameter to `DefaultSearchService` and `SearchExecutionService`. The default value is true, which means that total hits will always be computed accurately, even if they exceed the search engines threshold for accurate hit calculation. Change this parameter to `null`, to use the default threshold, pass an integer value to set a specific one.
6+
- [Indexing] Added `id` column as new primary key to `generic_data_index_queue`. Please make sure to execute migrations.
7+
- [Searching] Added `trackTotalHits` parameter to `DefaultSearchService` and `SearchExecutionService`. The default value is true, which means that total hits will always be computed accurately, even if they exceed the search engines threshold for accurate hit calculation. Change this parameter to `null`, to use the default threshold, pass an integer value to set a specific one.
78

89
## Upgrade to 2.1.0
910
- Added support for Symfony 7

doc/02_Configuration/03_Index_Management.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,27 @@ pimcore_generic_data_index:
6969
max_batch_size: 400
7070
```
7171

72+
#### Related elements
73+
74+
The indexing queue is automatically populated whenever an element undergoes an update operation. This process includes not only the modified element itself but also any related elements. By default, this indexing occurs asynchronously through Symfony Messenger.
75+
76+
For scenarios requiring immediate processing, you can temporarily switch to synchronous mode by utilizing the `SynchronousProcessingRelatedIdsServiceInterface`.
77+
78+
Available methods are:
79+
80+
| Method | Description |
81+
|--------|-------------|
82+
| `enable()` | Activates synchronous processing mode |
83+
| `disable()` | Reverts to asynchronous processing mode |
84+
| `isEnabled()` | Returns the current processing mode status |
85+
86+
:::info
87+
88+
Currently the `SynchronousProcessingRelatedIdsServiceInterface` interface does not influence the behavior of delete operations. They are always processed synchronously.
89+
90+
:::
91+
92+
7293
### Repairing Indices
7394

7495
Sometimes it might be needed to delete and recreate the index from the Pimcore database

src/Entity/IndexQueue.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@ class IndexQueue
2929
public const TABLE = 'generic_data_index_queue';
3030

3131
#[ORM\Id]
32+
#[ORM\Column(type: 'bigint')]
33+
private int $id;
34+
3235
#[ORM\Column(type: 'integer', options: ['unsigned' => true])]
3336
private int $elementId;
3437

35-
#[ORM\Id]
3638
#[ORM\Column(type: 'string', length: 20)]
3739
private string $elementType;
3840

@@ -48,6 +50,18 @@ class IndexQueue
4850
#[ORM\Column(type: 'bigint', options: ['unsigned' => true, 'default' => 0])]
4951
private string $dispatched;
5052

53+
public function getId(): int
54+
{
55+
return $this->id;
56+
}
57+
58+
public function setId(int $id): IndexQueue
59+
{
60+
$this->id = $id;
61+
62+
return $this;
63+
}
64+
5165
public function getElementId(): int
5266
{
5367
return $this->elementId;

src/EventSubscriber/AssetIndexUpdateSubscriber.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Pimcore\Bundle\GenericDataIndexBundle\Enum\SearchIndex\IndexQueueOperation;
1717
use Pimcore\Bundle\GenericDataIndexBundle\Installer;
1818
use Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueue\QueueMessagesDispatcher;
19+
use Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueue\SynchronousProcessingRelatedIdsServiceInterface;
1920
use Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueue\SynchronousProcessingServiceInterface;
2021
use Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueueServiceInterface;
2122
use Pimcore\Event\AssetEvents;
@@ -31,7 +32,8 @@ public function __construct(
3132
private IndexQueueServiceInterface $indexQueueService,
3233
private Installer $installer,
3334
private QueueMessagesDispatcher $queueMessagesDispatcher,
34-
private SynchronousProcessingServiceInterface $synchronousProcessing
35+
private SynchronousProcessingServiceInterface $synchronousProcessing,
36+
private SynchronousProcessingRelatedIdsServiceInterface $synchronousProcessingRelatedIds
3537
) {
3638
}
3739

@@ -54,7 +56,8 @@ public function updateAsset(AssetEvent $event): void
5456
->updateIndexQueue(
5557
element: $event->getAsset(),
5658
operation: IndexQueueOperation::UPDATE->value,
57-
processSynchronously: $this->synchronousProcessing->isEnabled()
59+
processSynchronously: $this->synchronousProcessing->isEnabled(),
60+
enqueueRelatedItemsAsync: $this->synchronousProcessingRelatedIds->isEnabled() === false
5861
)
5962
->commit();
6063

src/EventSubscriber/DataObjectIndexUpdateSubscriber.php

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@
1616
use Pimcore\Bundle\GenericDataIndexBundle\Enum\SearchIndex\IndexQueueOperation;
1717
use Pimcore\Bundle\GenericDataIndexBundle\Installer;
1818
use Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueue\QueueMessagesDispatcher;
19+
use Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueue\SynchronousProcessingRelatedIdsServiceInterface;
1920
use Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueue\SynchronousProcessingServiceInterface;
2021
use Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueueServiceInterface;
2122
use Pimcore\Bundle\GenericDataIndexBundle\Traits\LoggerAwareTrait;
2223
use Pimcore\Event\DataObjectEvents;
2324
use Pimcore\Event\Model\DataObjectEvent;
24-
use Pimcore\Model\DataObject\AbstractObject;
25+
use Pimcore\Model\DataObject\Service;
2526
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
2627

2728
/**
@@ -35,7 +36,8 @@ public function __construct(
3536
private readonly Installer $installer,
3637
private readonly IndexQueueServiceInterface $indexQueueService,
3738
private readonly QueueMessagesDispatcher $queueMessagesDispatcher,
38-
private readonly SynchronousProcessingServiceInterface $synchronousProcessing
39+
private readonly SynchronousProcessingServiceInterface $synchronousProcessing,
40+
private readonly SynchronousProcessingRelatedIdsServiceInterface $synchronousProcessingRelatedIds
3941
) {
4042
}
4143

@@ -62,19 +64,20 @@ public function updateDataObject(DataObjectEvent $event): void
6264
return;
6365
}
6466

65-
$inheritanceBackup = AbstractObject::getGetInheritedValues();
66-
AbstractObject::setGetInheritedValues(true);
67+
$dataObject = $event->getObject();
68+
Service::useInheritedValues(true, fn () =>
69+
$this->indexQueueService
70+
->updateIndexQueue(
71+
$dataObject,
72+
IndexQueueOperation::UPDATE->value,
73+
$this->synchronousProcessing->isEnabled(),
74+
$dataObject->hasChildren(includingUnpublished: true),
75+
$this->synchronousProcessingRelatedIds->isEnabled() === false
76+
)
77+
->commit()
78+
);
6779

68-
$this->indexQueueService
69-
->updateIndexQueue(
70-
element: $event->getObject(),
71-
operation: IndexQueueOperation::UPDATE->value,
72-
processSynchronously: $this->synchronousProcessing->isEnabled()
73-
)
74-
->commit();
7580
$this->queueMessagesDispatcher->dispatchQueueMessages();
76-
77-
AbstractObject::setGetInheritedValues($inheritanceBackup);
7881
}
7982

8083
public function deleteDataObject(DataObjectEvent $event): void
@@ -83,11 +86,13 @@ public function deleteDataObject(DataObjectEvent $event): void
8386
return;
8487
}
8588

89+
$dataObject = $event->getObject();
8690
$this->indexQueueService
8791
->updateIndexQueue(
88-
element: $event->getObject(),
89-
operation: IndexQueueOperation::DELETE->value,
90-
processSynchronously: $this->synchronousProcessing->isEnabled()
92+
$dataObject,
93+
IndexQueueOperation::DELETE->value,
94+
$this->synchronousProcessing->isEnabled(),
95+
$dataObject->hasChildren(includingUnpublished: true)
9196
)
9297
->commit();
9398
$this->queueMessagesDispatcher->dispatchQueueMessages();

src/EventSubscriber/DocumentIndexUpdateSubscriber.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Pimcore\Bundle\GenericDataIndexBundle\Enum\SearchIndex\IndexQueueOperation;
1717
use Pimcore\Bundle\GenericDataIndexBundle\Installer;
1818
use Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueue\QueueMessagesDispatcher;
19+
use Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueue\SynchronousProcessingRelatedIdsServiceInterface;
1920
use Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueue\SynchronousProcessingServiceInterface;
2021
use Pimcore\Bundle\GenericDataIndexBundle\Service\SearchIndex\IndexQueueServiceInterface;
2122
use Pimcore\Event\DocumentEvents;
@@ -31,7 +32,8 @@ public function __construct(
3132
private IndexQueueServiceInterface $indexQueueService,
3233
private Installer $installer,
3334
private QueueMessagesDispatcher $queueMessagesDispatcher,
34-
private SynchronousProcessingServiceInterface $synchronousProcessing
35+
private SynchronousProcessingServiceInterface $synchronousProcessing,
36+
private SynchronousProcessingRelatedIdsServiceInterface $synchronousProcessingRelatedIds
3537
) {
3638
}
3739

@@ -54,7 +56,8 @@ public function updateDocument(DocumentEvent $event): void
5456
->updateIndexQueue(
5557
element: $event->getDocument(),
5658
operation: IndexQueueOperation::UPDATE->value,
57-
processSynchronously: $this->synchronousProcessing->isEnabled()
59+
processSynchronously: $this->synchronousProcessing->isEnabled(),
60+
enqueueRelatedItemsAsync: $this->synchronousProcessingRelatedIds->isEnabled() === false
5861
)
5962
->commit();
6063

src/Installer.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
use Doctrine\DBAL\Schema\SchemaException;
2222
use Pimcore;
2323
use Pimcore\Bundle\GenericDataIndexBundle\Entity\IndexQueue;
24-
use Pimcore\Bundle\GenericDataIndexBundle\Migrations\Version20240325081139;
24+
use Pimcore\Bundle\GenericDataIndexBundle\Migrations\Version20251009110653;
2525
use Pimcore\Extension\Bundle\Installer\Exception\InstallationException;
2626
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
2727

@@ -40,7 +40,7 @@ public function __construct(
4040

4141
public function getLastMigrationVersionClassName(): ?string
4242
{
43-
return Version20240325081139::class;
43+
return Version20251009110653::class;
4444
}
4545

4646
/**
@@ -89,6 +89,7 @@ private function installIndexQueueTable(Schema $schema): void
8989
{
9090
if (!$schema->hasTable(IndexQueue::TABLE)) {
9191
$queueTable = $schema->createTable(IndexQueue::TABLE);
92+
$queueTable->addColumn('id', 'bigint', ['autoincrement' => true]);
9293
$queueTable->addColumn('elementId', 'integer', ['notnull' => true, 'unsigned' => true]);
9394
$queueTable->addColumn('elementType', 'string', ['notnull' => true, 'length' => 20]);
9495
$queueTable->addColumn('elementIndexName', 'string', ['notnull' => true, 'length' => 255]);
@@ -100,7 +101,8 @@ private function installIndexQueueTable(Schema $schema): void
100101
'default' => 0,
101102
]);
102103

103-
$queueTable->setPrimaryKey(['elementId', 'elementType']);
104+
$queueTable->setPrimaryKey(['id']);
105+
$queueTable->addUniqueIndex(['elementId', 'elementType'], IndexQueue::TABLE . '_element_id_type');
104106
$queueTable->addIndex(['dispatched'], IndexQueue::TABLE . '_dispatched');
105107
$queueTable->addIndex(['operationTime'], IndexQueue::TABLE . '_operation_time');
106108
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
/**
5+
* This source file is available under the terms of the
6+
* Pimcore Open Core License (POCL)
7+
* Full copyright and license information is available in
8+
* LICENSE.md which is distributed with this source code.
9+
*
10+
* @copyright Copyright (c) Pimcore GmbH (https://www.pimcore.com)
11+
* @license Pimcore Open Core License (POCL)
12+
*/
13+
14+
namespace Pimcore\Bundle\GenericDataIndexBundle\Message;
15+
16+
use Pimcore\Bundle\GenericDataIndexBundle\Enum\SearchIndex\ElementType;
17+
18+
/**
19+
* @internal
20+
*/
21+
final readonly class EnqueueRelatedIdsMessage
22+
{
23+
public function __construct(
24+
private int $elementId,
25+
private ElementType $elementType,
26+
private string $operation,
27+
private bool $addParentElement
28+
) {
29+
}
30+
31+
public function getElementId(): int
32+
{
33+
return $this->elementId;
34+
}
35+
36+
public function getElementType(): ElementType
37+
{
38+
return $this->elementType;
39+
}
40+
41+
public function getOperation(): string
42+
{
43+
return $this->operation;
44+
}
45+
46+
public function getAddParentElement(): bool
47+
{
48+
return $this->addParentElement;
49+
}
50+
}

0 commit comments

Comments
 (0)