[Progress News] [Progress OpenEdge ABL] Integrating Corticon Decision Services: Modern Asynchronous Invocation Patterns with Event-Driven Notification

  • Thread starter Thread starter Thierry Ciot
  • Start date Start date
Status
Not open for further replies.
T

Thierry Ciot

Guest

Introduction​


When integrating a Progress Corticon decision service into your JavaScript applications, handling asynchronous (async) operations correctly is critical, as decision services are an async function.

This blog presents three common async invocation patterns—using async/await propagation, a synchronous facade with an immediately invoked async function (IIAFE) and Promise chaining with .then()—all wrapped in a simple event-driven design that notifies when the decision service completes.

These patterns are demonstrated in this sample on the Corticon public Github.

As a historical note, decision services became asynchronous when we introduced support for service callout in Corticon V2.0.

The Heart of the Integration: runDecisionService​


Before we dive into the patterns, let’s look at the core async function that executes the Corticon rules engine—a common element to the three patterns presented below:

Code:
async function runDecisionService() {

try {

…

// Await the async decision service execution
const result = await window.corticonEngine.execute(payload, configuration);

…

} catch (e) {

alert('Unexpected exception executing the rules: ’ + e);

throw e;

}

}

This function uses modern async/await for clean, readable asynchronous calls and implements error handling. The code reads sequentially, and the execution is also sequential. That is, this function will return when the decision service has completed.

Three Ways to Invoke the Decision Service​


1. Async/Await Propagation — Async All the Way

You typically have a call stack of functions executing before the decision service is invoked. In this sample, we illustrate this condition with f1() calling f2() calling runDecisionService.

Code:
async function f1() {
console.log(“In f1 (async)”);
await f2();
}

async function f2() {
console.log(“In f2 (async)”);
await runDecisionService();
}

How it works:

  • Each function in the call stack is declared async
  • Each awaits the next, creating a clear, sequential flow that reads
    synchronously
  • Errors propagate naturally via try/catch

Pros:

  • Clean, readable code
  • Easy error handling
  • Modern JavaScript best practice

Cons:

  • Requires async propagation throughout the call chain, which can be
    intrusive in legacy or synchronous-heavy codebases
  • Main thread is blocked until the decision service has completed
    (typically, decision services execute very fast, but if yours is
    blocking the UI too long you may want to consider the options below)

2. Synchronous Facade with an IIAFE

Code:
function f1Sync() {

console.log(“In f1Sync (sync)”);

f2Sync();

console.log(“Exiting f1Sync before decision service completes”);

}

function f2Sync() {

console.log(“In f2Sync (sync)”);

(async () => {

console.log(“Invoking decision service inside IIAFE”);

const result = await runDecisionService();

console.log(“Decision service completed inside IIAFE”);

eventEmitter.emit(‘dsDone’, result);

})();

}

How it works:

  • The main call stack remains synchronous
  • Async logic runs inside IIAFE
  • f2Sync() returns immediately, but the async call happens in the background
  • Upon completion, a custom event (dsDone) is emitted to notify listeners

Pros:

  • Integrates async operations without marking all callers async
  • Keeps synchronous APIs intact
  • UI not “frozen” until decision service completes
  • Event-driven design lets other parts of the app respond when the decision service completes

Cons:

  • Callers don’t get the async result directly (must listen for events)
  • Slightly more complex pattern to understand initially

3. Promise Chaining with .then()

Code:
function f1SyncWithThen() {

console.log(“In f1SyncWithThen (sync)”);

f2SyncWithThen();

console.log(“Exiting f1SyncWithThen before decision service completes”);

}

function f2SyncWithThen() {

console.log(“In f2SyncWithThen (sync)”);

console.log(“Invoking decision service with .then()”);

runDecisionService()

.then(result => {

console.log(“Decision service completed with .then()”);

eventEmitter.emit(‘dsDone’, result);

})

.catch(error => {

console.error(“Error in decision service (with .then()):”, error);

alert("Error executing the decision service: " + error);

});

console.log(“Proceeding after invoking decision service with .then()”);

}

How it works:

  • The call stack remains synchronous
  • Uses Promise chaining (.then()) to handle async results
  • Emits an event upon completion
  • Includes error handling via .catch()

Pros:

  • Familiar pattern for Promise handling
  • Works well in environments without async/await
  • Easy to add error handling

Cons:

  • Slightly less readable than async/await
  • Can become nested with multiple async steps

Event-Driven Notifications​


The sample on the Corticon public Github page also introduces a simple EventEmitter to allow your app to respond when the decision service completes:

Code:
class EventEmitter {

constructor() { this.events = {}; }

on(event, listener) {

if (!this.events[event]) this.events[event] = [];

this.events[event].push(listener);

return this;

}

emit(event, …args) {

if (!this.events[event]) return false;

this.events[event].forEach(listener => listener(…args));

return true;

}

}

const eventEmitter = new EventEmitter();

// Listen for decision service completion event
eventEmitter.on(‘dsDone’, (result) => {

console.log(“Event: Decision Service Completed”);

// Further UI updates or workflows can be triggered here

});

This pattern decouples your UI or business logic from the async decision service invocation, promoting clean separation and easier maintenance.

Choosing the Approach that Works for You​


Here is a table summarizing the pros and cons of the patterns as presented in the sample on the Corticon public Github page:

PatternWhen to UseProsCons
Async/Await PropagationNew projects or full async controlReadable, linear flow; easy error handlingAsync "coloring" spreads through code
Synchronous Facade (IIAFE)Integration into legacy or synchronous APIsKeeps call stack sync; event notificationsMore complex; no direct return values
Promise Chaining (.then())Preferring classic Promises or older envs Familiar; works everywhereLess readable with multiple async steps



Take the next step and enroll in free training, or learn more about Corticon.js.

Continue reading...
 
Status
Not open for further replies.
Back
Top