@tiledesk/tiledesk-server 2.15.4 → 2.15.5
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/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
🚀 IN PRODUCTION 🚀
|
|
6
6
|
(https://www.npmjs.com/package/@tiledesk/tiledesk-server/v/2.3.77)
|
|
7
7
|
|
|
8
|
+
# 2.15.5
|
|
9
|
+
- Fixed email flooding when smart assignment is active and there are no operators available
|
|
10
|
+
|
|
8
11
|
# 2.15.4
|
|
9
12
|
- Updated endpoint to get project users adding the query parameter "trashed" in order to obtain also the trashed users.
|
|
10
13
|
- Added endpoint /restore to restore a deleted project user
|
package/app.js
CHANGED
|
@@ -200,7 +200,7 @@ var faqBotHandler = require('./services/faqBotHandler');
|
|
|
200
200
|
faqBotHandler.listen();
|
|
201
201
|
|
|
202
202
|
var pubModulesManager = require('./pubmodules/pubModulesManager');
|
|
203
|
-
pubModulesManager.init({express:express, mongoose:mongoose, passport:passport, databaseUri:databaseUri, routes:{}, jobsManager:jobsManager});
|
|
203
|
+
pubModulesManager.init({express:express, mongoose:mongoose, passport:passport, databaseUri:databaseUri, routes:{}, jobsManager:jobsManager, tdCache:tdCache});
|
|
204
204
|
|
|
205
205
|
jobsManager.listen(); //listen after pubmodules to enabled queued *.queueEnabled events
|
|
206
206
|
|
package/package.json
CHANGED
|
@@ -14,6 +14,7 @@ var winston = require('../../config/winston');
|
|
|
14
14
|
var RoleConstants = require("../../models/roleConstants");
|
|
15
15
|
var ChannelConstants = require("../../models/channelConstants");
|
|
16
16
|
var cacheUtil = require('../../utils/cacheUtil');
|
|
17
|
+
const { TdCache } = require('../../utils/TdCache');
|
|
17
18
|
|
|
18
19
|
const messageEvent = require('../../event/messageEvent');
|
|
19
20
|
var mongoose = require('mongoose');
|
|
@@ -40,6 +41,23 @@ if (pKey) {
|
|
|
40
41
|
let apiUrl = process.env.API_URL || configGlobal.apiUrl;
|
|
41
42
|
winston.debug('********* RequestNotification apiUrl: ' + apiUrl);
|
|
42
43
|
|
|
44
|
+
/** Redis cache for throttling pooled-request email. Injected by app (shared TdCache) or lazy-created fallback. */
|
|
45
|
+
let _pooledEmailTdCache = null;
|
|
46
|
+
function getPooledEmailCache() {
|
|
47
|
+
if (_pooledEmailTdCache) return _pooledEmailTdCache;
|
|
48
|
+
const fallback = new TdCache({
|
|
49
|
+
host: process.env.CACHE_REDIS_HOST,
|
|
50
|
+
port: process.env.CACHE_REDIS_PORT,
|
|
51
|
+
password: process.env.CACHE_REDIS_PASSWORD
|
|
52
|
+
});
|
|
53
|
+
fallback.connect();
|
|
54
|
+
_pooledEmailTdCache = fallback;
|
|
55
|
+
return _pooledEmailTdCache;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** TTL in seconds: do not send pooled email again for the same request within this window (avoids flooding when smart assignment retries) */
|
|
59
|
+
const POOLED_EMAIL_THROTTLE_TTL = Number(process.env.POOLED_EMAIL_THROTTLE_TTL) || cacheUtil.defaultTTL;
|
|
60
|
+
|
|
43
61
|
class RequestNotification {
|
|
44
62
|
|
|
45
63
|
constructor() {
|
|
@@ -48,7 +66,18 @@ class RequestNotification {
|
|
|
48
66
|
this.enabled = false;
|
|
49
67
|
}
|
|
50
68
|
winston.debug("RequestNotification this.enabled: "+ this.enabled);
|
|
51
|
-
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Reuse app's TdCache instance instead of opening a new Redis connection (optional, called by PubModulesManager).
|
|
73
|
+
* @param {TdCache} tdCache - shared Redis cache from app.get('redis_client')
|
|
74
|
+
*/
|
|
75
|
+
setTdCache(tdCache) {
|
|
76
|
+
if (tdCache && typeof tdCache.setNX === 'function') {
|
|
77
|
+
_pooledEmailTdCache = tdCache;
|
|
78
|
+
winston.debug("RequestNotification using shared TdCache for pooled email throttle");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
52
81
|
|
|
53
82
|
listen() {
|
|
54
83
|
|
|
@@ -892,6 +921,18 @@ sendAgentEmail(projectid, savedRequest) {
|
|
|
892
921
|
return winston.warn("RequestNotification savedRequest.snapshot is null :(. You are closing an old request?");
|
|
893
922
|
}
|
|
894
923
|
|
|
924
|
+
// Throttle: send pooled email only once per request within TTL (avoids flooding when smart assignment keeps retrying)
|
|
925
|
+
const requestId = (savedRequest._id || savedRequest.id).toString();
|
|
926
|
+
const pooledEmailKey = 'pooled_request_email:' + requestId;
|
|
927
|
+
try {
|
|
928
|
+
const shouldSend = await getPooledEmailCache().setNX(pooledEmailKey, '1', POOLED_EMAIL_THROTTLE_TTL);
|
|
929
|
+
if (!shouldSend) {
|
|
930
|
+
return winston.debug("RequestNotification pooled email already sent for request " + requestId + " (Redis throttle, TTL " + POOLED_EMAIL_THROTTLE_TTL + "s)");
|
|
931
|
+
}
|
|
932
|
+
} catch (redisErr) {
|
|
933
|
+
winston.warn("RequestNotification Redis setNX for pooled email throttle failed, skipping send", { error: redisErr, requestId });
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
895
936
|
|
|
896
937
|
|
|
897
938
|
var snapshotAgents = savedRequest; //riassegno varibile cosi nn cambio righe successive
|
|
@@ -175,6 +175,7 @@ class PubModulesManager {
|
|
|
175
175
|
winston.debug("PubModulesManager init");
|
|
176
176
|
|
|
177
177
|
this.jobsManager = config.jobsManager;
|
|
178
|
+
this.tdCache = config.tdCache;
|
|
178
179
|
|
|
179
180
|
try {
|
|
180
181
|
this.appRules = require('./rules/appRules');
|
|
@@ -631,6 +632,9 @@ class PubModulesManager {
|
|
|
631
632
|
// job_here
|
|
632
633
|
if (this.emailNotification) {
|
|
633
634
|
try {
|
|
635
|
+
if (this.tdCache) {
|
|
636
|
+
this.emailNotification.requestNotification.setTdCache(this.tdCache);
|
|
637
|
+
}
|
|
634
638
|
// this.emailNotification.requestNotification.listen();
|
|
635
639
|
this.jobsManager.listenEmailNotification(this.emailNotification);
|
|
636
640
|
winston.info("PubModulesManager emailNotification started.");
|
package/utils/TdCache.js
CHANGED
|
@@ -76,7 +76,18 @@ class TdCache {
|
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
79
|
+
/**
|
|
80
|
+
* Set key only if it does not exist, with TTL (seconds). Returns true if key was set, false if key already existed.
|
|
81
|
+
* Uses Redis SET key value EX ttl NX to avoid email/notification flooding.
|
|
82
|
+
*/
|
|
83
|
+
async setNX(key, value, ttlSeconds) {
|
|
84
|
+
return new Promise((resolve, reject) => {
|
|
85
|
+
this.client.set(key, value, 'EX', ttlSeconds, 'NX', (err, reply) => {
|
|
86
|
+
if (err) return reject(err);
|
|
87
|
+
resolve(reply === 'OK');
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
}
|
|
80
91
|
|
|
81
92
|
|
|
82
93
|
|