Async process inside success event
See original GitHub issueI’m having some trouble leveraging rule-chaining to add some runtime facts based on facts already in the Almanac like described here https://github.com/CacheControl/json-rules-engine/blob/master/docs/almanac.md#retrieve-fact-values-when-handling-events
I’ve modified https://github.com/CacheControl/json-rules-engine/blob/master/examples/07-rule-chaining.js to provide an primitive example of what I’m trying to do
/*
* This is an advanced example demonstrating rules that passed based off the
* results of other rules by adding runtime facts. It also demonstrates
* accessing the runtime facts after engine execution.
*
* Usage:
* node ./examples/07-rule-chaining.js
*
* For detailed output:
* DEBUG=json-rules-engine node ./examples/07-rule-chaining.js
*/
require('colors');
const { Engine } = require('../dist').Engine
/**
* Setup a new engine
*/
const engine = new Engine();
/**
* Rule for identifying people who may like screwdrivers
*/
const drinkRule = {
conditions: {
all: [
{
fact: 'drinksOrangeJuice',
operator: 'equal',
value: true,
},
{
fact: 'enjoysVodka',
operator: 'equal',
value: true,
},
],
},
event: { type: 'drinks-screwdrivers' },
priority: 10, // IMPORTANT! Set a higher priority for the drinkRule, so it runs first
};
engine.addRule(drinkRule);
/**
* Register listeners with the engine for rule success and failure
*/
let facts;
engine
.on('success', async (event, almanac) => {
console.log(`${facts.accountId + ' DID '.green}meet conditions for the ${event.type.underline} rule.`);
return new Promise((resolve) => {
setTimeout(() => {
console.log('promise resolved');
resolve();
}, 0);
});
})
.on('failure', (event) => {
console.log(`${facts.accountId} did ${'NOT'.red} meet conditions for the ${event.type.underline} rule.`);
});
// define fact(s) known at runtime
facts = {
accountId: 'washington',
drinksOrangeJuice: true,
enjoysVodka: true,
isSociable: true,
};
engine
.run(facts) // first run, using washington's facts
.then(() => {
console.log('engine run completed');
})
.catch();
/*
* OUTPUT:
*
* washington DID meet conditions for the drinks-screwdrivers rule.
* engine run completed
* promise resolved
*/
I would expect the success event to complete before the engine run finishes like so:
/*
* OUTPUT:
*
* washington DID meet conditions for the drinks-screwdrivers rule.
* promise resolved
* engine run completed
*/
Here’s a more concrete example based on my use case. I’m reading some facts from the Almanac, and I plan to assign a runtime fact based on those values.
const { Engine } = require('../dist').Engine
/**
* Setup a new engine
*/
require('colors');
const engine = new Engine();
/**
* Rule for identifying people who may like screwdrivers
*/
const drinkRule = {
conditions: {
all: [
{
fact: 'drinksOrangeJuice',
operator: 'equal',
value: true,
},
{
fact: 'enjoysVodka',
operator: 'equal',
value: true,
},
],
},
event: { type: 'drinks-screwdrivers' },
priority: 10, // IMPORTANT! Set a higher priority for the drinkRule, so it runs first
};
engine.addRule(drinkRule);
/**
* Register listeners with the engine for rule success and failure
*/
let facts;
engine
.on('success', async (event, almanac) => {
almanac.addRuntimeFact('screwdriverAficionado', true);
console.log(`${facts.accountId + ' DID '.green}meet conditions for the ${event.type.underline} rule.`);
let someInput;
someInput = await almanac.factValue('someInput');
someInput = await almanac.factValue('someInput');
someInput = await almanac.factValue('someInput');
someInput = await almanac.factValue('someInput');
someInput = await almanac.factValue('someInput');
someInput = await almanac.factValue('someInput');
someInput = await almanac.factValue('someInput');
someInput = await almanac.factValue('someInput');
someInput = await almanac.factValue('someInput');
almanac.addRuntimeFact(`newFact`, someInput);
console.log('resolved input', someInput);
})
.on('failure', (event) => {
console.log(`${facts.accountId} did ${'NOT'.red} meet conditions for the ${event.type.underline} rule.`);
});
// define fact(s) known at runtime
facts = {
accountId: 'washington',
drinksOrangeJuice: true,
enjoysVodka: true,
isSociable: true,
someInput: [1, 2, 3],
};
engine
.run(facts)
.then((results) => {
console.log('engine run completed');
// console.log(results);
})
.catch();
/*
* OUTPUT:
*
* washington DID meet conditions for the drinks-screwdrivers rule.
* engine run completed
* resolved input [ 1, 2, 3 ]
*/
And if I remove some of those async processes, then I get my expected behavior
...
engine
.on('success', async (event, almanac) => {
almanac.addRuntimeFact('screwdriverAficionado', true);
console.log(`${facts.accountId + ' DID '.green}meet conditions for the ${event.type.underline} rule.`);
let someInput;
someInput = await almanac.factValue('someInput');
almanac.addRuntimeFact(`newFact`, someInput);
console.log('resolved input', someInput);
})
...
/*
* OUTPUT:
*
* washington DID meet conditions for the drinks-screwdrivers rule.
* resolved input [ 1, 2, 3 ]
* engine run completed
*/
Issue Analytics
- State:
- Created 3 years ago
- Comments:6 (4 by maintainers)
Top Results From Across the Web
Understanding the Event Loop, Callbacks, Promises, and ...
The callback just allows you to be informed of when an asynchronous task has completed and handles the success or failure of the...
Read more >Asynchronous Programming with Async and Await - Visual Basic
A synchronous method returns when its work is complete (step 5), but an async method returns a task value when its work is...
Read more >Is there a built-in way to have an async method fire an event ...
If you need callback, the simplest is to pass a delegate. Methods can implicitly work as delegates. Events are useful if you need...
Read more >How to wait for an async task to complete inside an E2E test
Any Lambda function that is triggered asynchronously (e.g. from an EventBridge event, S3 upload, DynamoDB stream, SQS message); A Step Functions ...
Read more >How to use promises - Learn web development | MDN
With a promise-based API, the asynchronous function starts the operation and returns a Promise object. You can then attach handlers to this ...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I’ve taken a crack at this in #237 - relatively easy fix since EventEmitter2 supports this out of the box. Comments welcome. I still have some docs to write and examples to tweak, but I think this is functionally code complete. Since this is a breaking change, I’ve got at least 1 other breaking change I’d like to into into this next release, so I’m shooting for a release in the next two weeks.
@iamzoh @naveen-shetty if you’d like to confirm the fix, you can
npm install json-rules-engine@6.0.0-alpha-3
.This feature is now available in v6.0.0. See changelog