Completed
Push — master ( f2f9ef...8d6f66 )
by Fike
56s queued 19s
created

lib/Execution/Executor.js   A

Complexity

Total Complexity 17
Complexity/F 1.89

Size

Lines of Code 99
Function Count 9

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 0
wmc 17
c 1
b 0
f 0
nc 1
mnd 1
bc 13
fnc 9
dl 0
loc 99
rs 10
bpm 1.4443
cpm 1.8888
noi 0

1 Function

Rating   Name   Duplication   Size   Complexity  
B Executor.js ➔ Executor 0 80 1
1
var SDK = require('@ama-team/voxengine-sdk')
2
var TimeoutException = SDK.Concurrent.TimeoutException
3
var timeout = SDK.Concurrent.timeout
4
var CancellationToken = SDK.Concurrent.CancellationToken
5
var Slf4j = require('@ama-team/voxengine-sdk').Logger.Slf4j
6
var Objects = require('../Utility').Objects
7
8
/**
9
 * @class
10
 *
11
 * @implements {IExecutor}
12
 *
13
 * @param {IExecutionContext} ctx
14
 * @param {object} [options]
15
 */
16
function Executor (ctx, options) {
17
  var self = this
18
  options = options || {}
19
  var logger = Slf4j.factory(options.logger, 'ama-team.vsf.execution.executor')
20
21
  /**
22
   * @inheritDoc
23
   */
24
  this.execute = function (fn, args) {
25
    return fn.apply(ctx, args || [])
26
  }
27
28
  /**
29
   * @inheritDoc
30
   */
31
  this.promise = function (fn, args) {
32
    try {
33
      return Promise.resolve(self.execute(fn, args))
34
    } catch (e) {
35
      return Promise.reject(e)
36
    }
37
  }
38
39
  /**
40
   * @param {THandler} handler
41
   * @param {CancellationToken} [parent]
42
   */
43
  function tokenFactory (handler, parent) {
44
    var deps = parent ? [parent] : []
45
    return new CancellationToken(deps, 'handler `' + handler.id + '`')
46
  }
47
48
  /**
49
   * @param {THandler} handler
50
   * @param {CancellationToken} [token]
51
   * @param {*[]} [args]
52
   * @param {number} tokenArg
53
   * @return {Function}
54
   */
55
  function callbackFactory (handler, args, token, tokenArg) {
56
    return function (resolve, reject) {
57
      var message = 'Handler `' + handler.id + '` has exceeded it\'s timeout ' +
58
        'of ' + handler.timeout + ' ms'
59
      logger.warn(message)
60
      var error = new TimeoutException(message)
61
      args[tokenArg].cancel()
62
      if (!Objects.isObject(handler.onTimeout) || !Objects.isFunction(handler.onTimeout.handler)) {
63
        return reject(error)
64
      }
65
      args = args.slice().concat(error)
66
      return self
67
        .runHandler(handler.onTimeout, args, token, tokenArg)
68
        .then(resolve, function (e) { reject(e) })
69
    }
70
  }
71
72
  /**
73
   * @inheritDoc
74
   */
75
  this.runHandler = function (handler, args, token, tokenArg) {
76
    logger.debug('Running handler `{}`', handler.id)
77
    args = args ? args.slice() : []
78
    tokenArg = typeof tokenArg === 'number' ? tokenArg : args.length
79
    args[tokenArg] = tokenFactory(handler, token)
80
    var promise = self.promise(handler.handler, args)
81
    if (typeof handler.timeout === 'number' && handler.timeout >= 0) {
82
      logger.trace('Scheduling handler `{}` timeout in {} ms', handler.id,
83
        handler.timeout)
84
      var message = handler.id + ' has exceeded it\'s execution timeout of ' +
85
        handler.timeout
86
      var callback = callbackFactory(handler, args, token, tokenArg)
87
      promise = timeout(promise, handler.timeout, callback, message)
88
    }
89
    return promise
90
  }
91
92
  this.getContext = function () {
93
    return ctx
94
  }
95
}
96
97
module.exports = {
98
  Executor: Executor
99
}
100