|
@@ -65,6 +65,38 @@ class ElasticsearchDelegator {
|
|
|
this.indexName = indexName;
|
|
this.indexName = indexName;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * return information object to connect to ES
|
|
|
|
|
+ * @return {object} { host, httpAuth, indexName}
|
|
|
|
|
+ */
|
|
|
|
|
+ getConnectionInfo() {
|
|
|
|
|
+ let indexName = 'crowi';
|
|
|
|
|
+ let host = this.esUri;
|
|
|
|
|
+ let httpAuth = '';
|
|
|
|
|
+
|
|
|
|
|
+ const elasticsearchUri = this.configManager.getConfig('crowi', 'app:elasticsearchUri');
|
|
|
|
|
+
|
|
|
|
|
+ const url = new URL(elasticsearchUri);
|
|
|
|
|
+ if (url.pathname !== '/') {
|
|
|
|
|
+ host = `${url.protocol}//${url.host}`;
|
|
|
|
|
+ indexName = url.pathname.substring(1); // omit heading slash
|
|
|
|
|
+
|
|
|
|
|
+ if (url.username != null && url.password != null) {
|
|
|
|
|
+ httpAuth = `${url.username}:${url.password}`;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ host,
|
|
|
|
|
+ httpAuth,
|
|
|
|
|
+ indexName,
|
|
|
|
|
+ };
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ async init() {
|
|
|
|
|
+ return this.normalizeIndices();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
async getInfo() {
|
|
async getInfo() {
|
|
|
const info = await this.client.nodes.info();
|
|
const info = await this.client.nodes.info();
|
|
|
if (!info._nodes || !info.nodes) {
|
|
if (!info._nodes || !info.nodes) {
|
|
@@ -94,88 +126,79 @@ class ElasticsearchDelegator {
|
|
|
return { esVersion, esNodeInfos };
|
|
return { esVersion, esNodeInfos };
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * return information object to connect to ES
|
|
|
|
|
- * @return {object} { host, httpAuth, indexName}
|
|
|
|
|
- */
|
|
|
|
|
- getConnectionInfo() {
|
|
|
|
|
- let indexName = 'crowi';
|
|
|
|
|
- let host = this.esUri;
|
|
|
|
|
- let httpAuth = '';
|
|
|
|
|
|
|
+ async getInfoForAdmin() {
|
|
|
|
|
+ const { client, indexName, aliasName } = this;
|
|
|
|
|
|
|
|
- const elasticsearchUri = this.configManager.getConfig('crowi', 'app:elasticsearchUri');
|
|
|
|
|
|
|
+ const tmpIndexName = `${indexName}-tmp`;
|
|
|
|
|
|
|
|
- const url = new URL(elasticsearchUri);
|
|
|
|
|
- if (url.pathname !== '/') {
|
|
|
|
|
- host = `${url.protocol}//${url.host}`;
|
|
|
|
|
- indexName = url.pathname.substring(1); // omit heading slash
|
|
|
|
|
|
|
+ const { indices } = await client.indices.stats({ index: `${indexName}*`, ignore_unavailable: true, metric: ['docs', 'store', 'indexing'] });
|
|
|
|
|
|
|
|
- if (url.username != null && url.password != null) {
|
|
|
|
|
- httpAuth = `${url.username}:${url.password}`;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ const aliases = await client.indices.getAlias({ index: `${indexName}*` });
|
|
|
|
|
+ const isExistsMainIndex = aliases[indexName] != null;
|
|
|
|
|
+ const isMainIndexHasAlias = isExistsMainIndex && aliases[indexName].aliases != null && aliases[indexName].aliases[aliasName] != null;
|
|
|
|
|
+ const isExistsTmpIndex = aliases[tmpIndexName] != null;
|
|
|
|
|
+ const isTmpIndexHasAlias = isExistsTmpIndex && aliases[tmpIndexName].aliases != null && aliases[tmpIndexName].aliases[aliasName] != null;
|
|
|
|
|
+
|
|
|
|
|
+ const isNormalized = isExistsMainIndex && isMainIndexHasAlias && !isExistsTmpIndex && !isTmpIndexHasAlias;
|
|
|
|
|
|
|
|
return {
|
|
return {
|
|
|
- host,
|
|
|
|
|
- httpAuth,
|
|
|
|
|
- indexName,
|
|
|
|
|
|
|
+ indices,
|
|
|
|
|
+ aliases,
|
|
|
|
|
+ isNormalized,
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- async init() {
|
|
|
|
|
- return this.initIndices();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
- * build index
|
|
|
|
|
|
|
+ * rebuild index
|
|
|
*/
|
|
*/
|
|
|
- async buildIndex() {
|
|
|
|
|
|
|
+ async rebuildIndex() {
|
|
|
const { client, indexName, aliasName } = this;
|
|
const { client, indexName, aliasName } = this;
|
|
|
|
|
|
|
|
const tmpIndexName = `${indexName}-tmp`;
|
|
const tmpIndexName = `${indexName}-tmp`;
|
|
|
|
|
|
|
|
- // reindex to tmp index
|
|
|
|
|
- await this.createIndex(tmpIndexName);
|
|
|
|
|
- await client.reindex({
|
|
|
|
|
- waitForCompletion: false,
|
|
|
|
|
- body: {
|
|
|
|
|
- source: { index: indexName },
|
|
|
|
|
- dest: { index: tmpIndexName },
|
|
|
|
|
- },
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ // reindex to tmp index
|
|
|
|
|
+ await this.createIndex(tmpIndexName);
|
|
|
|
|
+ await client.reindex({
|
|
|
|
|
+ waitForCompletion: false,
|
|
|
|
|
+ body: {
|
|
|
|
|
+ source: { index: indexName },
|
|
|
|
|
+ dest: { index: tmpIndexName },
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
- // update alias
|
|
|
|
|
- await client.indices.updateAliases({
|
|
|
|
|
- body: {
|
|
|
|
|
- actions: [
|
|
|
|
|
- { add: { alias: aliasName, index: tmpIndexName } },
|
|
|
|
|
- { remove: { alias: aliasName, index: indexName } },
|
|
|
|
|
- ],
|
|
|
|
|
- },
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ // update alias
|
|
|
|
|
+ await client.indices.updateAliases({
|
|
|
|
|
+ body: {
|
|
|
|
|
+ actions: [
|
|
|
|
|
+ { add: { alias: aliasName, index: tmpIndexName } },
|
|
|
|
|
+ { remove: { alias: aliasName, index: indexName } },
|
|
|
|
|
+ ],
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
- // flush index
|
|
|
|
|
- await client.indices.delete({
|
|
|
|
|
- index: indexName,
|
|
|
|
|
- });
|
|
|
|
|
- await this.createIndex(indexName);
|
|
|
|
|
- await this.addAllPages();
|
|
|
|
|
|
|
+ // flush index
|
|
|
|
|
+ await client.indices.delete({
|
|
|
|
|
+ index: indexName,
|
|
|
|
|
+ });
|
|
|
|
|
+ await this.createIndex(indexName);
|
|
|
|
|
+ await this.addAllPages();
|
|
|
|
|
+ }
|
|
|
|
|
+ catch (error) {
|
|
|
|
|
+ logger.warn('An error occured while \'rebuildIndex\', normalize indices anyway.');
|
|
|
|
|
|
|
|
- // update alias
|
|
|
|
|
- await client.indices.updateAliases({
|
|
|
|
|
- body: {
|
|
|
|
|
- actions: [
|
|
|
|
|
- { add: { alias: aliasName, index: indexName } },
|
|
|
|
|
- { remove: { alias: aliasName, index: tmpIndexName } },
|
|
|
|
|
- ],
|
|
|
|
|
- },
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ const { searchEvent } = this;
|
|
|
|
|
+ searchEvent.emit('rebuildingFailed', error);
|
|
|
|
|
+
|
|
|
|
|
+ throw error;
|
|
|
|
|
+ }
|
|
|
|
|
+ finally {
|
|
|
|
|
+ await this.normalizeIndices();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // remove tmp index
|
|
|
|
|
- await client.indices.delete({ index: tmpIndexName });
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- async initIndices() {
|
|
|
|
|
|
|
+ async normalizeIndices() {
|
|
|
const { client, indexName, aliasName } = this;
|
|
const { client, indexName, aliasName } = this;
|
|
|
|
|
|
|
|
const tmpIndexName = `${indexName}-tmp`;
|
|
const tmpIndexName = `${indexName}-tmp`;
|