Description
Introduction
I have a Node.js Facebook Messenger Bot built with Bottender.js & Machina.js.
Bottender connects to Facebook and offloads events to Machina for handling. Machina manages the conversation flow - in terms of states.
Packages and their versions
- Machina -
v 4.0.2
- Node.js -
v 10.16.0
, - Bottender -
v 0.15.17
Problem statement
I'm using BehavioralFSM instances across the bot. Let's explore this code snippet:
const machina = require('machina');
const contactUsFsm = new machina.BehavioralFsm({
namespace: 'contact-us-fsm',
initialState: 'uninitialized',
states: {
uninitialized: {
async messengerPostback(context, payload){
// handles postback events from FB
},
async messengerText(context, payload) {
// handles text responses from FB
}
},
getContactInfo: {
_onEnter(context) {
this.hasInput = false; // gets updated in `getEmail` & `getPhone` states.
this.timer = setTimeout(
() => {
if(!this.hasInput()) {
// send user another prompt to provide their contact info
} else {
//cancel this timer & reset to the initial state
this.transition(context, )
}
},
12000 // 12s
)
},
async messengerText(context, payload) {
// once this handler is triggered, update 'hasInput'
this.hasInput = true;
// if they provide an email, take them to 'getPhone' state
// if they provide a phone, take them to 'getEmail' state
}
},
getEmail: {
// handles both 'SKIP EMAIL' functionality and actual data
},
getPhone: {
// handles both 'SKIP PHONE' functionality and actual data
},
sendContactInfo: {
// send this data to an external API
}
}
});
A user is required to provide either their phone number
or email address
. If they don't do this in 15s
, we prompt then again. This timer doesn't always work for concurrent users. See below.
hasInput
is used to track if a user has provided either phone number or email address so as to cancel the initial timeout
which prompts them for contact info after 15s of inactivity.
The other failing part is:
I'd like to watch out for SUBMIT PHONE
or SUBMIT EMAIL
. The getEmail
and getPhone
states allow the user to click a button to skip the state (i.e. if they already have provided one contact info, they do not have to provide the second one). There's another timeout that sends the available contact info to an external API (basically transitions to sendContactInfo
state)after 2 minutes of inactivity. I.e. If the user doesn't click on either SUBMIT PHONE
or SUBMIT_EMAIL
buttons. The challenge with this functionality as it is now is machina
has a shared FSM between concurrent users so when a user fails clicks on Submit buttons and another clicks, the timer are both reset or the this
keyword only works for the first user. Subsequent users are ignored.
Any ideas are welcome!