@cumulus/es-client 18.3.5 → 18.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/executions.js ADDED
@@ -0,0 +1,99 @@
1
+ //@ts-check
2
+
3
+ const Logger = require('@cumulus/logger');
4
+
5
+ const { getEsClient, defaultIndexAlias } = require('./search');
6
+
7
+ const log = new Logger({ sender: '@cumulus/es-client/executions' });
8
+
9
+ /**
10
+ * Generates a list of execution record IDs from an Elasticsearch Index based on a collection ID
11
+ *
12
+ * @param {Object} esClient - The Elasticsearch client object.
13
+ * @param {string} index - The name of the Elasticsearch index.
14
+ * @param {string} collectionId - The ID of the collection to match.
15
+ * @param {number} batchSize - The number of records to fetch in each batch.
16
+ * @returns {Promise<Array<string>>} A promise that resolves to an array of record IDs.
17
+ * @throws {Error} Throws an error if fetching the record IDs fails.
18
+ */
19
+ const _fetchEsRecordIds = async (esClient, index, collectionId, batchSize) => {
20
+ try {
21
+ const response = await esClient.client.search({
22
+ index,
23
+ type: 'execution',
24
+ scroll: process.env.ES_SCROLL_TIME || '5m',
25
+ body: {
26
+ query: {
27
+ match: {
28
+ collectionId,
29
+ },
30
+ },
31
+ _source: false,
32
+ },
33
+ size: batchSize,
34
+ });
35
+ return response.body.hits.hits.map((hit) => hit._id);
36
+ } catch (error) {
37
+ log.error(`Failed to get recordIds ${JSON.stringify(error)}`);
38
+ throw new Error(`Failed to fetch record IDs from Elasticsearch index ${index}: ${error.message}`);
39
+ }
40
+ };
41
+
42
+ /**
43
+ * Deletes executions in batches by collection ID.
44
+ *
45
+ * @param {Object} params - The parameters for the function.
46
+ * @param {string} [params.index] - The index to delete from.
47
+ * @param {string} params.collectionId - The ID of the collection.
48
+ * @param {number} params.batchSize - The size of the batches to delete.
49
+ * @returns {Promise<void>} A promise that resolves when the deletions are complete.
50
+ */
51
+ const batchDeleteExecutionsByCollection = async ({
52
+ index = defaultIndexAlias,
53
+ collectionId,
54
+ batchSize,
55
+ }) => {
56
+ try {
57
+ const esClient = await getEsClient();
58
+ if (!esClient.client) {
59
+ throw new Error('ES client not initialized!');
60
+ }
61
+ let recordIds;
62
+ let failures = 0;
63
+ while (recordIds === undefined || recordIds.length > 0) {
64
+ // eslint-disable-next-line no-await-in-loop
65
+ recordIds = await _fetchEsRecordIds(
66
+ esClient,
67
+ index,
68
+ collectionId,
69
+ batchSize
70
+ );
71
+ if (recordIds.length > 0) {
72
+ const body = recordIds.map((id) => ({
73
+ delete: { _index: index, _type: 'execution', _id: id },
74
+ }));
75
+ // eslint-disable-next-line no-await-in-loop
76
+ const response = await esClient.client.bulk({ body, refresh: 'true' });
77
+ if (response.body.errors) {
78
+ failures += 1;
79
+ log.error(`Bulk deletion encountered errors: ${JSON.stringify(
80
+ response.body.errors
81
+ )}`);
82
+ }
83
+ }
84
+ log.info(
85
+ `Successfully deleted ${recordIds.length} execution records from ${index} for collection ${collectionId}`
86
+ );
87
+ if (failures > 0) {
88
+ log.info(`${failures} errors encountered during deletion - please check logs for details`);
89
+ }
90
+ }
91
+ } catch (error) {
92
+ log.error(`Failed to delete execution records from ${index}: ${error.message}`);
93
+ throw error;
94
+ }
95
+ };
96
+
97
+ module.exports = {
98
+ batchDeleteExecutionsByCollection,
99
+ };
package/indexer.js CHANGED
@@ -90,7 +90,7 @@ async function genericRecordUpdate(esClient, id, doc, index, type, parent) {
90
90
  try {
91
91
  indexResponse = await actualEsClient.client.index(params);
92
92
  } catch (error) {
93
- if (error.name === 'ResponseError' && error.meta.body.message.includes('The security token included in the request is expired')) {
93
+ if (error.name === 'ResponseError' && error?.meta?.body?.message.includes('The security token included in the request is expired')) {
94
94
  logger.warn(`genericRecordUpdate encountered a ResponseError ${JSON.stringify(error)}, updating credentials and retrying`);
95
95
  await actualEsClient.refreshClient();
96
96
  indexResponse = await actualEsClient.client.index(params);
@@ -99,7 +99,7 @@ async function genericRecordUpdate(esClient, id, doc, index, type, parent) {
99
99
  }
100
100
  }
101
101
  } catch (error) {
102
- logger.error(`Error thrown on index ${JSON.stringify(error)}`);
102
+ logger.error(`Error thrown on index ${JSON.stringify(error.message)}`);
103
103
  throw error;
104
104
  }
105
105
  return indexResponse.body;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cumulus/es-client",
3
- "version": "18.3.5",
3
+ "version": "18.5.0",
4
4
  "description": "Utilities for working with Elasticsearch",
5
5
  "keywords": [
6
6
  "CUMULUS",
@@ -33,11 +33,11 @@
33
33
  "author": "Cumulus Authors",
34
34
  "license": "Apache-2.0",
35
35
  "dependencies": {
36
- "@aws-sdk/credential-providers": "^3.535.0",
37
- "@cumulus/common": "18.3.5",
38
- "@cumulus/errors": "18.3.5",
39
- "@cumulus/logger": "18.3.5",
40
- "@cumulus/message": "18.3.5",
36
+ "@aws-sdk/credential-providers": "^3.621.0",
37
+ "@cumulus/common": "18.5.0",
38
+ "@cumulus/errors": "18.5.0",
39
+ "@cumulus/logger": "18.5.0",
40
+ "@cumulus/message": "18.5.0",
41
41
  "@elastic/elasticsearch": "^5.6.20",
42
42
  "aws4": "^1.12.0",
43
43
  "lodash": "~4.17.21",
@@ -45,9 +45,9 @@
45
45
  "p-limit": "^1.2.0"
46
46
  },
47
47
  "devDependencies": {
48
- "@cumulus/aws-client": "18.3.5",
49
- "@cumulus/test-data": "18.3.5",
48
+ "@cumulus/aws-client": "18.5.0",
49
+ "@cumulus/test-data": "18.5.0",
50
50
  "p-each-series": "^2.1.0"
51
51
  },
52
- "gitHead": "04ba7f9aa1f20af96594f537e4c941b3f5d23ccc"
52
+ "gitHead": "37647f36bbcef2c591a207b6fd3361759035be03"
53
53
  }
package/search.js CHANGED
@@ -204,7 +204,7 @@ class EsClient {
204
204
  /**
205
205
  * Initializes a new instance of the `EsClient` class.
206
206
  *
207
- * @param {string} host - The host URL for the Elasticsearch instance.
207
+ * @param {string} [host] - The host URL for the Elasticsearch instance.
208
208
  * @param {boolean} [metrics=false] - A flag indicating whether metrics are enabled.
209
209
  */
210
210
  constructor(host, metrics = false) {
@@ -441,8 +441,8 @@ class Search extends BaseSearch {}
441
441
  /**
442
442
  * Initializes and returns an instance of an `EsClient` Class
443
443
  *
444
- * @param {string} host - The host URL for the Elasticsearch instance.
445
- * @param {boolean} metrics - A flag indicating whether metrics are enabled.
444
+ * @param {string} [host] - The host URL for the Elasticsearch instance.
445
+ * @param {boolean} [metrics] - A flag indicating whether metrics are enabled.
446
446
  * @returns {Promise<EsClient>} A promise that resolves to an instance of `EsClient`.
447
447
  */
448
448
  const getEsClient = async (host, metrics) => {