Commit a3825ab3e716583b5086c7e2a0516da1154fb1b2

Authored by Adhidarma Hadiwinoto
1 parent db834a8cbc
Exists in master

resend delay

Showing 3 changed files with 179 additions and 31 deletions Side-by-side Diff

... ... @@ -21,16 +21,17 @@
21 21 "author": "Adhidarma Hadiwinoto <gua@adhisimon.org>",
22 22 "license": "BSD",
23 23 "dependencies": {
24   - "mocha": "~2.2.5",
25   - "request": "~2.57.0",
26   - "strftime": "~0.9.2",
  24 + "ini": "~1.3.4",
  25 + "lru-cache": "^4.0.1",
27 26 "mathjs": "~1.7.0",
28   - "xmlrpc": "~1.3.1",
  27 + "minimist": "~1.2.0",
  28 + "mocha": "~2.2.5",
29 29 "node-simple-router": "~0.9.4-2",
  30 + "request": "~2.57.0",
30 31 "sate24": "git+http://gitlab.kodesumber.com/reload97/node-sate24.git",
31   - "winston": "~1.0.1",
32   - "ini": "~1.3.4",
33 32 "sate24-expresso": "git+http://gitlab.kodesumber.com/reload97/sate24-expresso.git",
34   - "minimist": "~1.2.0"
  33 + "strftime": "~0.9.2",
  34 + "winston": "~1.0.1",
  35 + "xmlrpc": "~1.3.1"
35 36 }
36 37 }
... ... @@ -0,0 +1,108 @@
  1 +var LRU = require('lru-cache');
  2 +var winston = require('winston');
  3 +
  4 +var logger;
  5 +var topupRequest;
  6 +var resendHandlers = LRU({max: 2000, maxAge: 1000 * 3600 * 36});
  7 +
  8 +function init(options) {
  9 + if (!options) {
  10 + console.log('Undefined options, terminating....');
  11 + process.exit(1);
  12 + }
  13 +
  14 + if (options.config) {
  15 + config = options.config;
  16 + } else {
  17 + console.log('Undefined options.config, terminating....')
  18 + process.exit(1);
  19 + }
  20 +
  21 + if (options.topupRequest) {
  22 + topupRequest = options.topupRequest;
  23 + } else {
  24 + console.log('Undefined options.topupRequest, terminating....')
  25 + process.exit(1);
  26 + }
  27 +
  28 + if (options.logger) {
  29 + logger = options.logger;
  30 + } else {
  31 + logger = new winston.Logger({
  32 + transports: [
  33 + new (winston.transports.Console)()
  34 + ]
  35 + });
  36 + }
  37 +}
  38 +
  39 +function cancel(_task) {
  40 + var requestId;
  41 + if (typeof task === 'string') {
  42 + requestId = task;
  43 + } else {
  44 + requestId = task.requestId;
  45 + }
  46 +
  47 + if (!requestId) {
  48 + logger.warn('Invalid task on cancelResendDelay');
  49 + return;
  50 + }
  51 +
  52 + var oldHandler = resendHandlers.get(requestId);
  53 + if (!oldHandler) {
  54 + return;
  55 + }
  56 +
  57 + logger.verbose('Canceling resend delay', {task: oldHandler.task});
  58 +
  59 + try {
  60 + if (oldHandler.handler) {
  61 + clearTimeout(oldHandler.handler);
  62 + }
  63 + }
  64 + catch(e) {};
  65 +
  66 + try {
  67 + resendHandlers.del(requestId);
  68 + }
  69 + catch(e) {};
  70 +}
  71 +
  72 +function register(task) {
  73 + if (!task.requestId) {
  74 + logger.warn('Invalid task on resendDelay')
  75 + return;
  76 + }
  77 +
  78 + if (!config || !config.globals || !Number(config.globals.auto_resend_delay_secs || !Number(config.globals.auto_resend_delay_max))) {
  79 + return;
  80 + }
  81 +
  82 + var retry = config.globals.auto_resend_delay_max;
  83 + var oldHandler = resendHandlers.get(task.requestId);
  84 + if (oldHandler) {
  85 + retry = oldHandler.retry - 1;
  86 + cancel(task);
  87 + }
  88 +
  89 + if (retry <= 0) {
  90 + logger.verbose('Resend delay retry exceeded', {task: task});
  91 + cancel(task);
  92 + return;
  93 + }
  94 +
  95 + logger.verbose('Registering resend delay task request', {task: task, delay: config.globals.auto_resend_delay_secs, retry: retry});
  96 + var handlerData = {
  97 + handler: setTimeout(topupRequest, config.globals.auto_resend_delay_secs * 1000, task),
  98 + task: task,
  99 + retry: retry
  100 + }
  101 +
  102 + resendHandlers.set(task.requestId, handlerData);
  103 +}
  104 +
  105 +
  106 +exports.init = init;
  107 +exports.cancel = cancel;
  108 +exports.register = register;
... ... @@ -2,18 +2,29 @@ var xmlrpc = require(&#39;xmlrpc&#39;);
2 2 var url = require('url');
3 3 var math = require('mathjs');
4 4 var winston = require('winston');
  5 +var resendDelay = require('./resend-delay.js');
  6 +var LRU = require('lru-cache');
5 7  
6 8 var aaa;
7 9 var logger;
8 10 var config;
9   -var callbackReport;
  11 +var _callbackReport;
10 12 var redisClient;
11 13  
12   -var max_retry = 2;
13   -var sleep_before_retry = 2000;
  14 +var taskHistory = LRU(max: 500, maxAge: 1000 * 3600 * 2);
14 15  
15 16 process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
16 17  
  18 +function callbackReport(requestId, responseCode, message) {
  19 + if (responseCode != '68') {
  20 + resendDelay.cancel(requestId);
  21 + } else {
  22 + getTaskFromHistory(requestId, function(err, archivedTask) {
  23 + resendDelay.register(archivedTask);
  24 + }
  25 + }
  26 + _callbackReport(requestId, responseCode, messsage);
  27 +}
17 28  
18 29 function createRedisClient(host, port) {
19 30 if (!host && !port) {
... ... @@ -28,22 +39,22 @@ function createRedisClient(host, port) {
28 39 }
29 40 }
30 41  
31   -function topupRequest(task, retry) {
  42 +function topupRequest(task) {
32 43 aaa.insertTaskToMongoDb(task);
33 44  
34   - getTaskFromRedis(task, function(err, archivedTask) {
35   - putTaskToRedis(task);
  45 + getTaskFromHistory(task, function(err, archivedTask) {
  46 + putTaskToHistory(task);
36 47  
37 48 if (archivedTask) {
38 49 logger.info('Task has been executed before, going to checkStatus', {task: task, archivedTask: archivedTask});
39   - checkStatus(task, retry);
  50 + checkStatus(task);
40 51 } else {
41   - _topupRequest(task, retry);
  52 + _topupRequest(task);
42 53 }
43 54 });
44 55 }
45 56  
46   -function _topupRequest(task, retry) {
  57 +function _topupRequest(task) {
47 58  
48 59 var partnerUrl = url.parse(config.h2h_out.partner);
49 60 var clientOptions = {
... ... @@ -77,17 +88,7 @@ function _topupRequest(task, retry) {
77 88 if (error) {
78 89  
79 90 logger.warn('XMLRPC Client Error', {requestId: task['requestId'], errorMessage: error});
80   -
81   - if (retry) {
82   -
83   - logger.info('Retrying topUpRequest (' + retry + ')');
84   - setTimeout(function() {
85   - topupRequest(task, retry - 1);
86   - }, sleep_before_retry);
87   -
88   - } else {
89   - callbackReport(task['requestId'], '91', 'Gangguan koneksi ke suplier: ' + error);
90   - }
  91 + callbackReport(task['requestId'], '91', 'Gangguan koneksi ke suplier: ' + error);
91 92 return;
92 93 }
93 94  
... ... @@ -221,7 +222,7 @@ function checkStatus(task) {
221 222 });
222 223 }
223 224  
224   -function start(_config, _callbackReport, options) {
  225 +function start(options) {
225 226 if (!options) {
226 227 console.log('Undefined options, terminating....');
227 228 process.exit(1);
... ... @@ -236,7 +237,7 @@ function start(_config, _callbackReport, options) {
236 237  
237 238 if (options.aaa) {
238 239 aaa = options.aaa;
239   - callbackReport = options.aaa.callbackReportWithPushToMongoDb;
  240 + _callbackReport = options.aaa.callbackReportWithPushToMongoDb;
240 241 } else {
241 242 console.log('Undefined options.aaa, terminating....')
242 243 process.exit(1);
... ... @@ -252,7 +253,14 @@ function start(_config, _callbackReport, options) {
252 253 });
253 254 }
254 255  
  256 + createRedisClient(config.globals.redis_host, config.globals.redis_port);
255 257 createServer();
  258 +
  259 + resendDelay.init({
  260 + config: config,
  261 + topupRequest: topupRequest,
  262 + logger: logger
  263 + });
256 264 }
257 265  
258 266 function parseSN(message, _config) {
... ... @@ -300,11 +308,31 @@ function parseSN(message, _config) {
300 308 }
301 309  
302 310 function getTaskKey(task, chipInfo) {
  311 + var requestId;
  312 +
  313 + if (typeof task === 'string') {
  314 + requestId = task;
  315 + } else {
  316 + requestId = task.requestId;
  317 + }
  318 +
303 319 if (!chipInfo && config && config.globals && config.globals.gateway_name) {
304 320 chipInfo = config.globals.gateway_name;
305 321 }
306 322  
307   - return chipInfo + 'hitachi.rid:' + task.requestId;
  323 + return chipInfo + 'hitachi.rid:' + requestId;
  324 +}
  325 +
  326 +
  327 +function putTaskToHistory(task, cb) {
  328 + var key = getTaskKey(task, config.globals.gateway_name);
  329 + logger.verbose('Saving task', {key: key, task: task});
  330 +
  331 + try {
  332 + taskHistory.set(key, JSON.parse(JSON.stringify(task)));
  333 + } catch (e) { }
  334 +
  335 + putTaskToRedis(task, cb);
308 336 }
309 337  
310 338 function putTaskToRedis(task, cb) {
... ... @@ -314,7 +342,6 @@ function putTaskToRedis(task, cb) {
314 342 }
315 343  
316 344 var key = getTaskKey(task, config.globals.gateway_name);
317   - logger.verbose('Saving task', {key: key, task: task});
318 345  
319 346 redisClient.set(key, JSON.stringify(task), function() {
320 347 redisClient.expire(key, 3600*24*30);
... ... @@ -324,6 +351,18 @@ function putTaskToRedis(task, cb) {
324 351 });
325 352 }
326 353  
  354 +function getTaskFromHistory(task, cb) {
  355 + var key = getTaskKey(task, config.globals.gateway_name);
  356 + var archive = taskHistory.get(key);
  357 +
  358 + if (archive) {
  359 + if (cb) { cb(null, archive); }
  360 + }
  361 + else {
  362 + getTaskFromRedis(task, cb);
  363 + }
  364 +}
  365 +
327 366 function getTaskFromRedis(task, cb) {
328 367 if (!redisClient) {
329 368 if (cb) { cb(null, null); }