jruizgit / rules

Durable Rules Engine
MIT License
1.14k stars 207 forks source link

Can events be retracted or deleted? #102

Open hjwgit opened 7 years ago

hjwgit commented 7 years ago

Hi, @jruizgit . I'm trying to use statechart to do some warnings. In my below use-case, a warning will be sent again if i received 3 events larger than 100 in 'dangerous' state.

var d = require('durable');
var m = d.m;
d.statechart('waterValve', {

  // initial state 'init' with two triggers
  init: [{
    to: 'safe',
    whenAll: m.water.lt(100),
    run: function (c) {
      console.log('init-->safe: ' + c.m.water);
    }
  },{
    to: 'dangerous',
    whenAll: m.water.gte(100),
    run: function (c) {
      console.log('init-->dangerous: ' + c.m.water);
    }
  }],

  // state 'safe'
  safe: [{
    to: 'safe',
    whenAll: m.water.lt(100),
    run: function (c) {
      console.log('safe-->safe: ' + c.m.water);
    }
  },{
    to: 'dangerous',
    whenAll: m.water.gte(100),
    run: function (c) {
      console.log('safe-->dangerous: ' + c.m.water);
      // TODO : warning
    }
  }],

  // state 'dangerous'
  dangerous: [{
    to: 'safe',
    whenAll: m.water.lt(100),
    run: function (c) {
      console.log('dangerous-->safe' + c.m.water);
    }
  },{
    to: 'dangerous',
    whenAll: m.water.gte(100),
    count: 3,
    run: function (c) {
      console.log('dangerous for 3 times' + c.m.length + JSON.stringify(m));
      // TODO : warning
    }
  }
  ],
});

d.runAll();

However, with the following input, events (1)(2) (> 100) will be stored in database and will cause a new warning if i received a event larger than 100 (event 5) after that.

(0)// 'init' to 'dangerous' state (0) curl -H "content-type: application/json" -X POST http://localhost:5000/waterValve/event -d '{"water": 20000}' (1) curl -H "content-type: application/json" -X POST http://localhost:5000/waterValve/event -d '{"water": 20000}' (2) curl -H "content-type: application/json" -X POST http://localhost:5000/waterValve/event -d '{"water": 20000}' (3)// 'dangerous' to 'safe' state (3) curl -H "content-type: application/json" -X POST http://localhost:5000/waterValve/event -d '{"water": 50}' (4)// 'safe' to 'dangerous' state (4) curl -H "content-type: application/json" -X POST http://localhost:5000/waterValve/event -d '{"water": 20000}' (5)// send warning again for just one post (5) curl -H "content-type: application/json" -X POST http://localhost:5000/stateValve/event -d '{"water": 20000}'

I was wondering if events (1) and (2) can be retracted or deleted when i receive event (3) ? Or is there some other types of rules that can solve my problem? Thanks!

jruizgit commented 7 years ago

Thanks for posting the question, let me look into this. Events are retracted before dispatch and should be observed only once.

jruizgit commented 7 years ago

I understand your scenario now. When moving from dangerous to safe, the events accumulated in the reflexive rule count will not be retracted (this is by design, one important principle: the rules engine never drops events). For this case I recommend you keep track of the count using the context state. For example:

var d = require('../libjs/durable');
var m = d.m, s = d.s;
d.statechart('waterValve', {

  // initial state 'init' with two triggers
  init: [{
    to: 'safe',
    whenAll: m.water.lt(100),
    run: function (c) {
      c.s.count = 0;
      console.log('init-->safe: ' + c.m.water);
    }
  },{
    to: 'dangerous',
    whenAll: m.water.gte(100),
    run: function (c) {
      c.s.count = 0;
      console.log('init-->dangerous: ' + c.m.water);
    }
  }],

  // state 'safe'
  safe: [{
    to: 'safe',
    whenAll: m.water.lt(100),
    run: function (c) {
      console.log('safe-->safe: ' + c.m.water);
    }
  },{
    to: 'dangerous',
    whenAll: m.water.gte(100),
    run: function (c) {
      console.log('safe-->dangerous: ' + c.m.water);
      // TODO : warning
    }
  }],

  // state 'dangerous'
  dangerous: [{
    to: 'safe',
    whenAll: m.water.lt(100),
    run: function (c) {
      c.s.count = 0;
      console.log('dangerous-->safe' + c.m.water);
    }
  },{
    to: 'dangerous',
    whenAll: m.water.gte(100),
    run: function (c) {
      c.s.count += 1;
      console.log('incrementing count');
      // TODO : warning
    }
  },{
    to: 'dangerous',
    whenAll: s.count.eq(3),
    run: function (c) {
      c.s.count = 0;
      console.log('dangerous for 3 times');
      // TODO : warning
    }
  }
  ],
});

d.runAll();
hjwgit commented 7 years ago

@jruizgit Thank you so much for your reply! That was very useful for me.