wingbot-mongodb 3.2.0 → 3.2.2
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/.eslintrc +1 -0
- package/.nyc_output/98a862df-b2a1-4d14-9176-6b0bada108f7.json +1 -0
- package/.nyc_output/processinfo/{cb79cd4d-6c45-40e4-b29a-e38af10c7c7c.json → 98a862df-b2a1-4d14-9176-6b0bada108f7.json} +1 -1
- package/.nyc_output/processinfo/index.json +1 -1
- package/package.json +1 -1
- package/src/BaseStorage.js +66 -3
- package/src/NotificationsStorage.js +22 -13
- package/src/StateStorage.js +30 -71
- package/.nyc_output/cb79cd4d-6c45-40e4-b29a-e38af10c7c7c.json +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"parent":null,"pid":
|
|
1
|
+
{"parent":null,"pid":81134,"argv":["/usr/local/bin/node","/Users/david/Development/wingbot-mongodb/node_modules/.bin/mocha","./test"],"execArgv":[],"cwd":"/Users/david/Development/wingbot-mongodb","time":1676533760202,"ppid":81133,"coverageFilename":"/Users/david/Development/wingbot-mongodb/.nyc_output/98a862df-b2a1-4d14-9176-6b0bada108f7.json","externalId":"","uuid":"98a862df-b2a1-4d14-9176-6b0bada108f7","files":["/Users/david/Development/wingbot-mongodb/src/BaseStorage.js","/Users/david/Development/wingbot-mongodb/src/defaultLogger.js","/Users/david/Development/wingbot-mongodb/src/AttachmentCache.js","/Users/david/Development/wingbot-mongodb/src/AuditLogStorage.js","/Users/david/Development/wingbot-mongodb/src/BotConfigStorage.js","/Users/david/Development/wingbot-mongodb/src/BotTokenStorage.js","/Users/david/Development/wingbot-mongodb/src/tokenFactory.js","/Users/david/Development/wingbot-mongodb/src/ChatLogStorage.js","/Users/david/Development/wingbot-mongodb/src/NotificationsStorage.js","/Users/david/Development/wingbot-mongodb/src/StateStorage.js"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"processes":{"
|
|
1
|
+
{"processes":{"98a862df-b2a1-4d14-9176-6b0bada108f7":{"parent":null,"children":[]}},"files":{"/Users/david/Development/wingbot-mongodb/src/BaseStorage.js":["98a862df-b2a1-4d14-9176-6b0bada108f7"],"/Users/david/Development/wingbot-mongodb/src/defaultLogger.js":["98a862df-b2a1-4d14-9176-6b0bada108f7"],"/Users/david/Development/wingbot-mongodb/src/AttachmentCache.js":["98a862df-b2a1-4d14-9176-6b0bada108f7"],"/Users/david/Development/wingbot-mongodb/src/AuditLogStorage.js":["98a862df-b2a1-4d14-9176-6b0bada108f7"],"/Users/david/Development/wingbot-mongodb/src/BotConfigStorage.js":["98a862df-b2a1-4d14-9176-6b0bada108f7"],"/Users/david/Development/wingbot-mongodb/src/BotTokenStorage.js":["98a862df-b2a1-4d14-9176-6b0bada108f7"],"/Users/david/Development/wingbot-mongodb/src/tokenFactory.js":["98a862df-b2a1-4d14-9176-6b0bada108f7"],"/Users/david/Development/wingbot-mongodb/src/ChatLogStorage.js":["98a862df-b2a1-4d14-9176-6b0bada108f7"],"/Users/david/Development/wingbot-mongodb/src/NotificationsStorage.js":["98a862df-b2a1-4d14-9176-6b0bada108f7"],"/Users/david/Development/wingbot-mongodb/src/StateStorage.js":["98a862df-b2a1-4d14-9176-6b0bada108f7"]},"externalIds":{}}
|
package/package.json
CHANGED
package/src/BaseStorage.js
CHANGED
|
@@ -33,12 +33,31 @@ function getNestedObjects (obj, nested, attr = null, ret = {}) {
|
|
|
33
33
|
|
|
34
34
|
class BaseStorage {
|
|
35
35
|
|
|
36
|
+
static netFailuresIntervalMs = 600000; // 10 minutes
|
|
37
|
+
|
|
38
|
+
static netFailuresCount = 0;
|
|
39
|
+
|
|
40
|
+
static _killing = null;
|
|
41
|
+
|
|
42
|
+
static _failStack = [];
|
|
43
|
+
|
|
44
|
+
static killer = () => setTimeout(() => {
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}, 10000);
|
|
47
|
+
|
|
48
|
+
static networkFailureErrorNames = [
|
|
49
|
+
'MongoServerSelectionError',
|
|
50
|
+
'MongoNetworkError',
|
|
51
|
+
'MongoNetworkTimeoutError',
|
|
52
|
+
'MongoTopologyClosedError'
|
|
53
|
+
];
|
|
54
|
+
|
|
36
55
|
/**
|
|
37
56
|
*
|
|
38
57
|
* @param {Db|{():Promise<Db>}} mongoDb
|
|
39
58
|
* @param {string} collectionName
|
|
40
59
|
* @param {{error:Function,log:Function}} [log] - console like logger
|
|
41
|
-
* @param {boolean} [isCosmo]
|
|
60
|
+
* @param {boolean|number} [isCosmo]
|
|
42
61
|
* @example
|
|
43
62
|
*
|
|
44
63
|
* const { BaseStorage } = require('winbot-mongodb');
|
|
@@ -67,7 +86,7 @@ class BaseStorage {
|
|
|
67
86
|
constructor (mongoDb, collectionName, log = defaultLogger, isCosmo = false) {
|
|
68
87
|
this._mongoDb = mongoDb;
|
|
69
88
|
this._collectionName = collectionName;
|
|
70
|
-
this._isCosmo = isCosmo;
|
|
89
|
+
this._isCosmo = typeof isCosmo === 'number' || isCosmo;
|
|
71
90
|
this._log = log;
|
|
72
91
|
|
|
73
92
|
/**
|
|
@@ -84,7 +103,11 @@ class BaseStorage {
|
|
|
84
103
|
|
|
85
104
|
this._fixtures = [];
|
|
86
105
|
|
|
87
|
-
if (isCosmo
|
|
106
|
+
if (typeof isCosmo === 'number') {
|
|
107
|
+
BaseStorage.netFailuresCount = isCosmo;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (this._isCosmo && !process.argv.some((a) => a.endsWith('mocha'))) {
|
|
88
111
|
process.nextTick(() => {
|
|
89
112
|
const hasUniqueIndex = this._indexes.some((i) => i.options.unique);
|
|
90
113
|
|
|
@@ -96,6 +119,45 @@ class BaseStorage {
|
|
|
96
119
|
}
|
|
97
120
|
}
|
|
98
121
|
|
|
122
|
+
/**
|
|
123
|
+
*
|
|
124
|
+
* @template T
|
|
125
|
+
* @param {{():T}} fn
|
|
126
|
+
* @returns {Promise<T>}
|
|
127
|
+
*/
|
|
128
|
+
_catchNetworkIssues (fn) {
|
|
129
|
+
return Promise.resolve(fn())
|
|
130
|
+
.catch((e) => {
|
|
131
|
+
this._detectNetworkIssueException(e);
|
|
132
|
+
throw e;
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @template {Error} T
|
|
138
|
+
* @param {T} e
|
|
139
|
+
* @returns {T}
|
|
140
|
+
*/
|
|
141
|
+
_detectNetworkIssueException (e) {
|
|
142
|
+
if (BaseStorage.netFailuresCount !== 0
|
|
143
|
+
&& BaseStorage.networkFailureErrorNames.includes(e.name)) {
|
|
144
|
+
|
|
145
|
+
const now = Date.now();
|
|
146
|
+
BaseStorage._failStack.push(now);
|
|
147
|
+
|
|
148
|
+
if (BaseStorage._failStack.length >= BaseStorage.netFailuresCount
|
|
149
|
+
&& BaseStorage._failStack.shift() > (now - BaseStorage.netFailuresIntervalMs)
|
|
150
|
+
&& BaseStorage._killing === null) {
|
|
151
|
+
|
|
152
|
+
this._log.error(`${this._collectionName}: KILLING APP DUE FREQUENT NETWORK ERRORS ${BaseStorage._failStack.length}`, e);
|
|
153
|
+
|
|
154
|
+
// let it alive for following ten seconds to process all logs
|
|
155
|
+
BaseStorage._killing = BaseStorage.killer() || null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return e;
|
|
159
|
+
}
|
|
160
|
+
|
|
99
161
|
preHeat () {
|
|
100
162
|
return this._getCollection();
|
|
101
163
|
}
|
|
@@ -201,6 +263,7 @@ class BaseStorage {
|
|
|
201
263
|
this._collection = c;
|
|
202
264
|
} catch (e) {
|
|
203
265
|
this._collection = null;
|
|
266
|
+
this._detectNetworkIssueException(e);
|
|
204
267
|
throw e;
|
|
205
268
|
}
|
|
206
269
|
}
|
|
@@ -303,13 +303,14 @@ class NotificationsStorage {
|
|
|
303
303
|
|
|
304
304
|
const findMissingIds = tasks
|
|
305
305
|
.reduce((arr, {
|
|
306
|
-
campaignId, senderId, pageId, sent
|
|
306
|
+
campaignId, senderId, pageId, sent, enqueue
|
|
307
307
|
}, i) => {
|
|
308
308
|
if (typeof res.upsertedIds[i] !== 'undefined') {
|
|
309
309
|
return arr;
|
|
310
310
|
}
|
|
311
311
|
arr.push({
|
|
312
312
|
i,
|
|
313
|
+
enqueue,
|
|
313
314
|
filter: {
|
|
314
315
|
campaignId, senderId, pageId, sent
|
|
315
316
|
}
|
|
@@ -321,23 +322,31 @@ class NotificationsStorage {
|
|
|
321
322
|
|
|
322
323
|
if (findMissingIds.length > 0) {
|
|
323
324
|
await Promise.all(findMissingIds
|
|
324
|
-
.map(({ filter, i }) => c.findOne(filter, {
|
|
325
|
+
.map(({ filter, i, enqueue }) => c.findOne(filter, {
|
|
325
326
|
projection: {
|
|
326
327
|
_id: 1, insEnqueue: 1, enqueue: 1, ups: 1
|
|
327
328
|
}
|
|
328
329
|
})
|
|
329
330
|
.then((found) => {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
? found.
|
|
339
|
-
: found.
|
|
340
|
-
|
|
331
|
+
if (!found) { // race condition occurred
|
|
332
|
+
missingIds.set(i, {
|
|
333
|
+
id: null,
|
|
334
|
+
insEnqueue: -1,
|
|
335
|
+
enqueue
|
|
336
|
+
});
|
|
337
|
+
} else {
|
|
338
|
+
const id = typeof found._id === 'string'
|
|
339
|
+
? found._id
|
|
340
|
+
: found._id.toHexString();
|
|
341
|
+
missingIds.set(i, {
|
|
342
|
+
id,
|
|
343
|
+
insEnqueue: found.insEnqueue,
|
|
344
|
+
enqueue: found.insEnqueue === found.enqueue
|
|
345
|
+
&& found.enqueue !== MAX_TS && found.ups !== 1
|
|
346
|
+
? found.enqueue + 1
|
|
347
|
+
: found.enqueue
|
|
348
|
+
});
|
|
349
|
+
}
|
|
341
350
|
})));
|
|
342
351
|
}
|
|
343
352
|
|
package/src/StateStorage.js
CHANGED
|
@@ -40,7 +40,7 @@ class StateStorage extends BaseStorage {
|
|
|
40
40
|
* @param {boolean|number} isCosmo - boolean or number of failures in last 10min to kill app
|
|
41
41
|
*/
|
|
42
42
|
constructor (mongoDb, collectionName = 'states', log = defaultLogger, isCosmo = false) {
|
|
43
|
-
super(mongoDb, collectionName, log,
|
|
43
|
+
super(mongoDb, collectionName, log, isCosmo);
|
|
44
44
|
|
|
45
45
|
this.addIndex(
|
|
46
46
|
{ senderId: 1, pageId: 1 },
|
|
@@ -51,10 +51,6 @@ class StateStorage extends BaseStorage {
|
|
|
51
51
|
{ name: LAST_INTERACTION_INDEX }
|
|
52
52
|
);
|
|
53
53
|
|
|
54
|
-
this._failStack = [];
|
|
55
|
-
|
|
56
|
-
this._failures = typeof isCosmo === 'number' ? isCosmo : 0;
|
|
57
|
-
|
|
58
54
|
if (isCosmo) {
|
|
59
55
|
this.addIndex(
|
|
60
56
|
{ name: 1 },
|
|
@@ -66,21 +62,6 @@ class StateStorage extends BaseStorage {
|
|
|
66
62
|
{ name: SEARCH }
|
|
67
63
|
);
|
|
68
64
|
}
|
|
69
|
-
|
|
70
|
-
this.failuresIntervalMs = 600000; // 10 minutes
|
|
71
|
-
|
|
72
|
-
this._killing = null;
|
|
73
|
-
|
|
74
|
-
this.networkFailureErrorNames = [
|
|
75
|
-
'MongoServerSelectionError',
|
|
76
|
-
'MongoNetworkError',
|
|
77
|
-
'MongoNetworkTimeoutError',
|
|
78
|
-
'MongoTopologyClosedError'
|
|
79
|
-
];
|
|
80
|
-
|
|
81
|
-
this.killer = () => setTimeout(() => {
|
|
82
|
-
process.exit(1);
|
|
83
|
-
}, 10000);
|
|
84
65
|
}
|
|
85
66
|
|
|
86
67
|
/**
|
|
@@ -118,59 +99,37 @@ class StateStorage extends BaseStorage {
|
|
|
118
99
|
* @returns {Promise<object>} - conversation state
|
|
119
100
|
*/
|
|
120
101
|
async getOrCreateAndLock (senderId, pageId, defaultState = {}, timeout = 300) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const c = await this._getCollection();
|
|
124
|
-
|
|
125
|
-
const $setOnInsert = {
|
|
126
|
-
state: defaultState,
|
|
127
|
-
lastSendError: null,
|
|
128
|
-
off: false
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
const $set = {
|
|
132
|
-
lock: now
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
const $lt = now - timeout;
|
|
136
|
-
|
|
137
|
-
const res = await c.findOneAndUpdate({
|
|
138
|
-
senderId,
|
|
139
|
-
pageId,
|
|
140
|
-
lock: { $lt }
|
|
141
|
-
}, {
|
|
142
|
-
$setOnInsert,
|
|
143
|
-
$set
|
|
144
|
-
}, {
|
|
145
|
-
upsert: true,
|
|
146
|
-
returnDocument: 'after',
|
|
147
|
-
projection: {
|
|
148
|
-
_id: 0
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
return res.value;
|
|
153
|
-
} catch (e) {
|
|
154
|
-
if (this._failures !== 0
|
|
155
|
-
&& this.networkFailureErrorNames.includes(e.name)) {
|
|
156
|
-
|
|
157
|
-
now = Date.now();
|
|
158
|
-
this._failStack.push(now);
|
|
159
|
-
|
|
160
|
-
if (this._failStack.length >= this._failures
|
|
161
|
-
&& this._failStack.shift() > (now - this.failuresIntervalMs)
|
|
162
|
-
&& this._killing === null) {
|
|
163
|
-
|
|
164
|
-
this._log.error(`StateStorage: KILLING APP DUE FREQUENT NETWORK ERRORS ${this._failStack.length}`, e);
|
|
165
|
-
|
|
166
|
-
// let it alive for following ten seconds to process all logs
|
|
167
|
-
this._killing = this.killer() || null;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
102
|
+
const now = Date.now();
|
|
103
|
+
const c = await this._getCollection();
|
|
170
104
|
|
|
171
|
-
|
|
172
|
-
|
|
105
|
+
const $setOnInsert = {
|
|
106
|
+
state: defaultState,
|
|
107
|
+
lastSendError: null,
|
|
108
|
+
off: false
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const $set = {
|
|
112
|
+
lock: now
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const $lt = now - timeout;
|
|
116
|
+
|
|
117
|
+
const res = await this._catchNetworkIssues(() => c.findOneAndUpdate({
|
|
118
|
+
senderId,
|
|
119
|
+
pageId,
|
|
120
|
+
lock: { $lt }
|
|
121
|
+
}, {
|
|
122
|
+
$setOnInsert,
|
|
123
|
+
$set
|
|
124
|
+
}, {
|
|
125
|
+
upsert: true,
|
|
126
|
+
returnDocument: 'after',
|
|
127
|
+
projection: {
|
|
128
|
+
_id: 0
|
|
129
|
+
}
|
|
130
|
+
}));
|
|
173
131
|
|
|
132
|
+
return res.value;
|
|
174
133
|
}
|
|
175
134
|
|
|
176
135
|
/**
|