Skip to content

Commit 87a10a9

Browse files
committed
feature: add the ability to recreate index by swapping new and old under a common alias
1 parent ae62419 commit 87a10a9

4 files changed

Lines changed: 89 additions & 12 deletions

File tree

src/CoreShop2VueStorefrontBundle/Bridge/ImporterFactory.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ public function __construct(PersisterFactory $persisterFactory)
2626
/**
2727
* @return array<ImporterFactory>
2828
*/
29-
public function create(?string $site = null, ?string $type = null, ?string $language = null, ?string $store = null, ?\DateTimeInterface $since = null): array
29+
public function create(?string $site = null, ?string $type = null, ?string $language = null, ?string $store = null, ?\DateTimeInterface $since = null, ?string $runTimestamp = null): array
3030
{
31-
$persisters = $this->persisterFactory->create($site, $type, $language, $store);
31+
$persisters = $this->persisterFactory->create($site, $type, $language, $store, $runTimestamp);
3232
$importers = [];
3333
foreach ($persisters as $config) {
3434
$importers[] = new ElasticsearchImporter($config['repository'], $config['persister'], $config['site'], $config['type'], $config['language'], $config['store'], $since);

src/CoreShop2VueStorefrontBundle/Bridge/PersisterFactory.php

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace CoreShop2VueStorefrontBundle\Bridge;
66

7+
use CoreShop2VueStorefrontBundle\Bridge\SwappingIndexService;
78
use ONGR\ElasticsearchBundle\Mapping\Converter;
89
use ONGR\ElasticsearchBundle\Mapping\IndexSettings;
910
use ONGR\ElasticsearchBundle\Service\IndexService;
@@ -77,7 +78,7 @@ public function __construct(ContainerInterface $container, Converter $converter,
7778
/**
7879
* @return array<array{persister: PersisterFactory, store: string, language: string, type: string}>
7980
*/
80-
public function create(?string $site = null, ?string $type = null, ?string $language = null, ?string $store = null): array
81+
public function create(?string $site = null, ?string $type = null, ?string $language = null, ?string $store = null, ?string $runTimestamp = null): array
8182
{
8283
$options = $this->resolver->resolve(['site' => $site, 'type' => $type, 'language' => $language, 'store' => $store]);
8384

@@ -115,16 +116,9 @@ public function create(?string $site = null, ?string $type = null, ?string $lang
115116
];
116117

117118
$indexName = $this->inject($this->elasticsearchConfig['index'], $variables);
118-
$settings = new IndexSettings(
119-
$className,
120-
$indexName,
121-
$indexName,
122-
$this->elasticsearchConfig['templates'][$className] ?? [],
123-
$this->inject($this->elasticsearchConfig['hosts'], $variables, true)
124-
);
125119
$indexSettings = new IndexSettings(
126120
$className,
127-
$indexName,
121+
$runTimestamp ? $indexName.'_'.$runTimestamp : $indexName,
128122
$indexName,
129123
array_replace_recursive(
130124
$indexSettings->getIndexMetadata(),
@@ -139,6 +133,10 @@ public function create(?string $site = null, ?string $type = null, ?string $lang
139133
$indexSettings
140134
);
141135

136+
if ($runTimestamp) {
137+
$indexService = new SwappingIndexService($indexService, $runTimestamp);
138+
}
139+
142140
$persisters[] = [
143141
'persister' => new EnginePersister($indexService, $this->documentMapperFactory, $language, $concreteStore),
144142
'site' => $name,
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace CoreShop2VueStorefrontBundle\Bridge;
6+
7+
use ONGR\ElasticsearchBundle\Service\IndexService;
8+
9+
class SwappingIndexService extends IndexService
10+
{
11+
private $runTimestamp;
12+
/**
13+
* @var IndexService
14+
*/
15+
private $baseIndexService;
16+
17+
public function __construct(IndexService $baseIndexService, string $runTimestamp)
18+
{
19+
$this->baseIndexService = $baseIndexService;
20+
$this->runTimestamp = $runTimestamp;
21+
}
22+
23+
/**
24+
* Flushes ES and adds extra steps needed for swapping (assign alias to new index, remove from old indices, drop old indices)
25+
*
26+
* @param array $params
27+
* @return array
28+
*/
29+
public function flush(array $params = []): array
30+
{
31+
$return = $this->baseIndexService->flush($params);
32+
33+
$indicesClient = $this->baseIndexService->getClient()->indices();
34+
$settings = $this->baseIndexService->indexSettings;
35+
36+
$oldIndices = null;
37+
// if alias doesn't exist, the previous index will have a clashing name with alias we're creating so we have to drop it
38+
if(!$indicesClient->existsAlias(['name' => $settings->getAlias()])) {
39+
$this->baseIndexService->dropIndex();
40+
}
41+
else {
42+
//get index names associated with alias
43+
$oldIndices = implode(',', array_keys($indicesClient->getAlias(['name' => $settings->getAlias()])));
44+
//delete alias from old indices
45+
$indicesClient->deleteAlias([
46+
"index" => $oldIndices,
47+
"name" => $settings->getAlias()
48+
]);
49+
}
50+
//assign alias to new index
51+
$indicesClient->putAlias([
52+
"index" => $settings->getIndexName(),
53+
"name" => $settings->getAlias()
54+
]);
55+
56+
if($oldIndices) {
57+
//drop old indices
58+
$indicesClient->delete([
59+
"index" => $oldIndices
60+
]);
61+
}
62+
63+
return $return;
64+
}
65+
66+
public function getBaseIndexService(): IndexService
67+
{
68+
return $this->baseIndexService;
69+
}
70+
71+
public function __call($method, $args)
72+
{
73+
if (!method_exists($this, $method) && method_exists($this->baseIndexService, $method)) {
74+
return $this->baseIndexService->$method($args);
75+
}
76+
}
77+
}

src/CoreShop2VueStorefrontBundle/Command/IndexCommand.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ protected function configure()
3535
->addArgument('language', InputArgument::OPTIONAL, 'Language to index')
3636
->addArgument('store', InputArgument::OPTIONAL, 'Site store to index')
3737
->addOption('updated-since', 's', InputOption::VALUE_OPTIONAL, 'Fetch objects updated in the relative timeframe ("5minute", "2hour", "1day", "yesterday" etc)')
38+
->addOption('swap', null, InputOption::VALUE_OPTIONAL, 'Do a full reingest by swapping indices', false)
3839
->setName('vsbridge:index-objects')
3940
->setDescription('Indexing objects of given type in vuestorefront');
4041
}
@@ -63,6 +64,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
6364
$language = $input->getArgument('language');
6465
$store = $input->getArgument('store');
6566

67+
$runTimestamp = date('YmdHis');
6668
$sinceDatetime = null;
6769
if (null !== $since = $input->getOption('updated-since')) {
6870
$sinceDatetime = new \Datetime();
@@ -78,7 +80,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
7880
$style->warning(sprintf('Indexing only updated since: %1$s', $sinceDatetime->format('c')));
7981
}
8082

81-
$importers = $this->importerFactory->create($site, $type, $language, $store, $sinceDatetime);
83+
$importers = $this->importerFactory->create($site, $type, $language, $store, $sinceDatetime, $input->getOption('swap') ? $runTimestamp : null);
8284

8385
/** @var ImporterInterface $importer */
8486
foreach ($importers as $importer) {

0 commit comments

Comments
 (0)