lib/queue.js
function (key, task, done, ttl) {
    const queue     = this.queue;
    const semaphore = this.semaphore;

    if (!ttl) ttl = this.ttl;


    const runTask = (res) => new Promise((resolve) =>
      task( (...args) => resolve(Response.setData(res, args)) )
    );


    const startThenRunTask = (lock_key) =>
      queue.start(key, Response.factory(ttl))
      .then(runTask)
      .then(queue.dequeue.bind(null, key))
      .then(() => semaphore.release(key, lock_key))
      .catch((err) => {
        semaphore.release(key, lock_key);
        throw err;
      })
    ;


    const startIfNotWaiting = () =>
      Promise.all([
        queue.isWaiting(key)
      , semaphore.lock(key)
      ])
      .then(([ is_waiting, lock_key ]) =>
        (!is_waiting && lock_key) ? startThenRunTask(lock_key) : null
      )

    return queue
      .add(key, done)
      .then(startIfNotWaiting)
    ;
  }
function (key, task, done, ttl) {
    const queue     = this.queue;
    const semaphore = this.semaphore;

    if (!ttl) ttl = this.ttl;


    const runTask = (res) => new Promise((resolve) =>
      task( (...args) => resolve(Response.setData(res, args)) )
    );


    const startThenRunTask = (lock_key) =>
      queue.start(key, Response.factory(ttl))
      .then(runTask)
      .then(queue.dequeue.bind(null, key))
      .then(() => semaphore.release(key, lock_key))
      .catch((err) => {
        semaphore.release(key, lock_key);
        throw err;
      })
    ;


    const startIfNotWaiting = () =>
      Promise.all([
        queue.isWaiting(key)
      , semaphore.lock(key)
      ])
      .then(([ is_waiting, lock_key ]) =>
        (!is_waiting && lock_key) ? startThenRunTask(lock_key) : null
      )

    return queue
      .add(key, done)
      .then(startIfNotWaiting)
    ;
  }
Queue up the given task using the given key as an identifier. @param {string} key @param {Function} task @param {Function} done @param {number} ttl - the time to live for the queue cache. @return {Queue}