Montacer Dkhilali
Montacer Dkhilali

Reputation: 399

Is there a way to send a TimeOut object from a step to an other in a dialog? - botBuilder v4 - Node.js

In one of my bot's dialog steps I'am lanching some operations in a setTimeout() function. The goal is to clear that TimeOut in an other step in some conditions.

async saveAdults(step) {
    if (step.result) {
      step.values.adults = step.result;
      const convId = step.context.activity.conversation.id;
      const format = "dddd DD MMMM YYYY";

      // Send partial notification in case of a delay of 5 minutes
      const data = {
        checkIn: step.values.checkIn,
        nights: step.values.nights,
        adults: "",
        children: ""
      };
      const timer = await sendPartialNotification(convId, data);
      // step.values.timer = timer;
      this.notificationProp.set(step.context, timer);
      await this.conversationState.saveChanges(step.context);
    }
    return await step.next();
  }
exports.sendPartialNotification = async (convId, data) => {
  const interval = 300000;
  const timer = setTimeout(() => {
    notify(convId, this.id, data, true);
  }, interval);
  return timer;
};
async notifyClient(step) {
  const timer = this.notificationProp.get(step.context);
  clearTimeout(timer);
  // …
}

Trying to store the TimeOut object in step.values.timer or in the conversation state throws this error that indicates that it is not possible to parse the Timeout Object ...

TypeError: Converting circular structure to JSON

As solution to this, I was thinking about storing the timer in Redis ..

Is there any ideas? Thanks.

Upvotes: 0

Views: 136

Answers (1)

Steven Kanberg
Steven Kanberg

Reputation: 6418

Use state, props, or equivalent to pass the value from one step to the next. In my example code below, I include a middle step asking if the client would like to cancel. This is purely for displaying output for the solution.

  1. Initiate the timer in a lead step.
async setTimer(step) {
  if (step.result) {
    const convId = step.context.activity.conversation.id;

    const data = {
      value1: someValue1,
      value2: someValue2
    };

    const timer = await sendPartialNotification(convId, data);

    this.notificationProp = { step: step.context, timer: timer };
    await this.conversationState.saveChanges(step.context);
  }
  return await step.next();
}
  1. Ask the client, in an intermediary step, if they would like to cancel the timer. I have the timer set for 10 secs.
    • If the user cancels, the timer is cleared.
    • If the client declines or fails to respond before 10 secs is up, the timer is unaffected and executes.
async askClient(step) {
  const timer = this.notificationProp.timer;

  if (timer._idleTimeout > 0) {
    const message = MessageFactory.text(
      'Cancel the timer?',
      null,
      'expectingInput'
    );
    return await step.prompt('confirmPrompt', message);
  }
}
  1. Lastly, output results and notify the client.
async notifyClient(step) {
  const stepResult = step.result;
  step.value = { timer: this.notificationProp.timer };

  if (stepResult === true) {
    console.log('TIMER PRE-CLEAR ', step.value.timer);

    const timer = step.value.timer;
    await clearTimeout(timer);

    console.log('TIMER POST-CLEAR', timer);
    step.context.sendActivity('Cancelling timer');
  } else {
    step.context.sendActivity('Timer not cancelled');
  }

  return await step.next();
}

Timer not cancelled and executes:

enter image description here

Timer cancelled:

enter image description here

Hope of help!

Upvotes: 1

Related Questions