@tiledesk/tiledesk-server
Version:
The Tiledesk server module
158 lines (129 loc) • 5.7 kB
JavaScript
;
const schedule = require('node-schedule');
const winston = require('../../../config/winston');
const Request = require("../../../models/request");
const requestService = require("../../../services/requestService");
/**
* Task scheduler for automatically closing agent unresponsive requests.
* Finds requests with agents that haven't been updated within a specified timeout
* and closes them automatically.
*/
class CloseAgentUnresponsiveRequestTask {
constructor() {
this.enabled = process.env.CLOSE_AGENT_UNRESPONSIVE_REQUESTS_ENABLE || "false";
this.cronExp = process.env.CLOSE_AGENT_UNRESPONSIVE_REQUESTS_CRON_EXPRESSION || '*/30 * * * *'; //every 30 minutes
this.queryAfterTimeout = parseInt(process.env.CLOSE_AGENT_UNRESPONSIVE_REQUESTS_AFTER_TIMEOUT) || 5 * 24 * 60 * 60 * 1000; //five days ago // 86400000 a day
this.queryLimit = parseInt(process.env.CLOSE_AGENT_UNRESPONSIVE_REQUESTS_QUERY_LIMIT) || 10;
this.queryProject = process.env.CLOSE_AGENT_UNRESPONSIVE_REQUESTS_QUERY_FILTER_ONLY_PROJECT;
this.delayBeforeClosing = parseInt(process.env.CLOSE_AGENT_UNRESPONSIVE_REQUESTS_DELAY) || 1000;
if (this.queryProject) {
winston.info("CloseAgentUnresponsiveRequestTask filter only by projects enabled: " + this.queryProject );
}
}
/**
* Starts the scheduler if enabled.
*/
run() {
if (this.enabled === "true") {
winston.info("CloseAgentUnresponsiveRequestTask started" );
this.scheduleUnresponsiveRequests();
} else {
winston.info("CloseAgentUnresponsiveRequestTask disabled" );
}
}
/**
* Schedules the recurring job to find and close unresponsive requests.
*/
scheduleUnresponsiveRequests() {
winston.info(
`CloseAgentUnresponsiveRequestTask task scheduleUnresponsiveRequests launched with ` +
`closeAfter: ${this.queryAfterTimeout} milliseconds, ` +
`cron expression: ${this.cronExp} and query limit: ${this.queryLimit}`
);
schedule.scheduleJob(this.cronExp, (fireDate) => {
winston.debug(`CloseAgentUnresponsiveRequestTask ScheduleUnresponsiveRequests job was supposed to run at ${fireDate}, but actually ran at ${new Date()}`);
this.findUnresponsiveRequests();
});
}
/**
* Finds unresponsive agent requests and schedules their closure.
* Queries for requests with agents that haven't been updated within the timeout period.
*/
findUnresponsiveRequests() {
const cutoffDate = new Date(Date.now() - this.queryAfterTimeout);
const query = {
hasBot: false,
status: { $lt: 1000 },
updatedAt: { $lte: cutoffDate },
workingStatus: { $ne: 'pending' }
};
if (this.queryProject) {
try {
query.id_project = JSON.parse(this.queryProject);
} catch (err) {
winston.error("CloseAgentUnresponsiveRequestTask error parsing queryProject filter", err);
return;
}
}
winston.debug("CloseAgentUnresponsiveRequestTask query",query);
//console.log("[CloseUnresponsive] Searching with query: ", query);
Request.find(query)
.sort({ updatedAt: 'asc' })
.limit(this.queryLimit)
.hint({ status: 1, hasBot: 1, updatedAt: 1 })
.exec((err, requests) => {
if (err) {
winston.error("CloseAgentUnresponsiveRequestTask error getting unresponsive requests ", err);
return;
}
if (!requests || requests.length === 0) {
winston.verbose("CloseAgentUnresponsiveRequestTask no unresponsive requests found ");
return;
}
//console.log("[CloseUnresponsive] Found ", requests.length, " unresponsive requests");
winston.verbose("CloseAgentUnresponsiveRequestTask: found " + requests.length + " unresponsive requests");
winston.debug("CloseAgentUnresponsiveRequestTask: found unresponsive requests ", requests);
this.scheduleRequestClosures(requests);
});
}
/**
* Schedules the closure of multiple requests with staggered delays.
* @param {Array} requests - Array of request objects to close
*/
scheduleRequestClosures(requests) {
requests.forEach((request, index) => {
// Stagger delays: 2 * delayBeforeClosing * (index + 1)
const delay = 2 * this.delayBeforeClosing * (index + 1);
winston.debug(`CloseAgentUnresponsiveRequestTask: scheduling closure with delay: ${delay}ms for request_id: ${request.request_id}`);
setTimeout(() => {
this.closeRequest(request);
}, delay);
});
}
/**
* Closes a single unresponsive request.
* @param {Object} request - The request object to close
*/
closeRequest(request) {
winston.debug(`CloseAgentUnresponsiveRequestTask: processing unresponsive request: ${request.first_text}`);
const closedBy = "_bot_unresponsive";
const shouldSkipStatsUpdate = false;
const shouldNotify = false;
requestService.closeRequestByRequestId(
request.request_id,
request.id_project,
shouldSkipStatsUpdate,
shouldNotify,
closedBy
).then(() => {
winston.info(`CloseAgentUnresponsiveRequestTask: Request closed with request_id: ${request.request_id}`);
}).catch((err) => {
const hideErrors = process.env.HIDE_CLOSE_REQUEST_ERRORS === true || process.env.HIDE_CLOSE_REQUEST_ERRORS === "true";
if (!hideErrors) {
winston.error(`CloseAgentUnresponsiveRequestTask: Error closing the request with request_id: ${request.request_id}`, err);
}
});
}
}
const closeAgentUnresponsiveRequestTask = new CloseAgentUnresponsiveRequestTask();
module.exports = closeAgentUnresponsiveRequestTask;