docs: function (evt, callback) {
  
      if (!this.doesContainProperties(evt)) {
        debug('does not match the containing properties check');
        return callback(null, null);
      }
  
      var self = this;
  
      //        self.shouldHandle(evt, sagaModel, function (err, doHandle) {
      this.shouldHandleEvent(evt, function (err, doHandle) {
        if (err) {
          return callback(err);
        }
  
        if (!doHandle) {
          return callback(null, null);
        }
  
        function retry (retryIn) {
          if (_.isNumber(retryIn)) {
            retryIn = randomBetween(0, retryIn);
          }
  
          if (_.isObject(retryIn) && _.isNumber(retryIn.from) && _.isNumber(retryIn.to)) {
            retryIn = randomBetween(retryIn.from, retryIn.to);
          }
  
          if (!_.isNumber(retryIn) || retryIn === 0) {
            retryIn = randomBetween(0, self.options ? self.options.retryOnConcurrencyTimeout : 800);
          }
  
          debug('retry in ' + retryIn + 'ms');
          setTimeout(function() {
            self.handle(evt, callback);
          }, retryIn);
        }
  
        async.waterfall([
  
          function (callb) {
            if (!self.id || !dotty.exists(evt, self.id)) {
              debug('has no id, generate new one');
  
              if (!self.getNewIdForThisSaga) {
                return self.sagaStore.getNewId(callb);
              }
  
              self.getNewIdForThisSaga(evt, callb);
            } else {
              debug('already has an id');
              callb(null, dotty.get(evt, self.id));
            }
          },
  
          function (id, callb) {
            self.sagaStore.get(id, function (err, data) {
              if (err) {
                return callb(err);
              }
  
              if (!data && self.existing) {
                debug('this saga only wants to be executed, if already existing');
                return callback(null, null);
              }
  
              var sagaModel = new SagaModel(id);
              if (data) {
                sagaModel.set(data);
                sagaModel.actionOnCommit = 'update';
              }
              callb(null, sagaModel);
            });
          },
  
          function (sagaModel, callb) {
  
            // attach commit function
            debug('attach commit function');
  
            /**
             * Commits the saga data and its commands.
             * @param {Function} clb The function, that will be called when this action is completed.
             *                       `function(err){}`
             */
            sagaModel.commit = function (clb) {
              async.parallel([
                function (callback) {
                  self.checkForId(sagaModel.getUndispatchedCommands(), callback);
                },
                function (callback) {
                  self.checkForId(sagaModel.getTimeoutCommands(), callback);
                }
              ], function (err) {
                if (err) {
                  debug(err);
                  return callback(err);
                }
                if (sagaModel.isDestroyed()) {
                  self.sagaStore.remove(sagaModel.id, clb);
                } else {
                  sagaModel.setCommitStamp(new Date());
  
                  var undispCmds = _.map(sagaModel.getUndispatchedCommands(), function (c) {
                    return { id: dotty.get(c, self.definitions.command.id), payload: c };
                  });
  
                  self.sagaStore.save(sagaModel.toJSON(), undispCmds, function (err) {
                    if (err instanceof ConcurrencyError) {
                      retry(clb);
                      return;
                    }
                    clb(err);
                  });
                }
              });
            };
  
            // attach addCommandToSend function
            debug('attach addCommandToSend function');
            /**
             * Adds the passed command to this model.
             * @param {Object} cmd The command that should be sent.
             */
            sagaModel.addCommandToSend = function (cmd) {
              if (!dotty.exists(cmd, self.definitions.command.meta) && dotty.exists(evt, self.definitions.event.meta) &&
                !!self.definitions.command.meta && !!self.definitions.event.meta) {
                dotty.put(cmd, self.definitions.command.meta, dotty.get(evt, self.definitions.event.meta));
              }
  
              sagaModel.addUnsentCommand(cmd);
            };
  
            // attach defineTimeout function
            debug('attach defineTimeout function');
            /**
             * Defines a timeout date and optional timeout commands, and adds them to this model.
             * @param {Date}  date The timeout date.
             * @param {Array} cmds The array of commands.
             */
            sagaModel.defineTimeout = function (date, cmds) {
              cmds = cmds || [];
              if (!_.isArray(cmds)) {
                cmds = [cmds];
              }
  
              cmds.forEach(function (cmd) {
                if (!dotty.exists(cmd, self.definitions.command.meta) && dotty.exists(evt, self.definitions.event.meta) &&
                  !!self.definitions.command.meta && !!self.definitions.event.meta) {
                  dotty.put(cmd, self.definitions.command.meta, dotty.get(evt, self.definitions.event.meta));
                }
              });
  
              sagaModel.addTimeout(date, cmds);
            };
  
            callb(null, sagaModel);
          },
  
          function (sagaModel, callb) {
            var sagaThis = {
              retry: function () {
                if (arguments.length === 0) {
                  return retry();
                }
  
                return retry(arguments[0]);
              }
            };
  
            self.shouldHandle(evt, sagaModel, function (err, doHandle) {
              if (err) {
                return callb(err);
              }
  
              if (!doHandle) {
                return callb(null, sagaModel);
              }
  
              self.sagaFn.call(sagaThis, self.getPayload(evt), sagaModel, function (err) {
                if (err) {
                  return callb(err);
                }
                callb(null, sagaModel);
              });
            });
          },
  
          function (sagaModel, callb) {
            // detach commit function
            debug('detach commit function');
            if (sagaModel.commit) {
              delete sagaModel.commit;
            }
  
            // detach addCommandToSend function
            debug('detach addCommandToSend function');
            if (sagaModel.addCommandToSend) {
              delete sagaModel.addCommandToSend;
            }
  
            // detach defineTimeout function
            debug('detach defineTimeout function');
            if (sagaModel.defineTimeout) {
              delete sagaModel.defineTimeout;
            }
            callb(null, sagaModel);
          }
  
        ], callback);
      });
    }