I'm having an issue where multiple users concurrently accessing the same dialog are having their prompt values mixed up. The dialog in question is an Order Status dialog where, among other things, the order number is prompted. I am seeing cases where User 1 queries Order A, User 2 queries Order B (at nearly the same time) and then both users receive information for Order B.
This is a complex dialog and sharing the complete code wouldn't be helpful, but here are a few points I feel may be relevant:
this.queryData = {}
in the constructor to initiate an object to hold all of the order query parameters I am prompting for, including order number.
return await step.prompt(TEXT_PROMPT, {
prompt: `Please provide your ${step.values.orderTypeText} number.`,
retryPrompt: `Please enter a valid ${step.values.orderTypeText} number.`,
});
this.queryData.orderNumber = step.result.trim().split(" ").splice(-1)[0];
And that's really it, unless there is some way that it's not the prompt value but the entire message that is getting send to the wrong user (but that seems quite unlikely, plus it is going to both users in this example).
I have considered instead of using this.queryData
to store the information in conversationState
, but I don't want to redo the code unless I can confirm this is an issue with the implementation I have used, specifically this.queryData
rather than some other issue.
For reference, here is the class definition, down to the end of the constructor:
class viewOrderDialog extends ComponentDialog {
constructor(dialogId, userDialogStateAccessor, userState, appInsightsClient, dialogState, conversationState) {
super(dialogId);
this.addDialog(new ChoicePrompt(CRITERIA_PROMPT));
this.addDialog(new TextPrompt(TEXT_PROMPT));
this.addDialog(new TextPrompt(LINE_PROMPT, this.validateLineNumber));
this.addDialog(new TextPrompt(EMAIL_PROMPT,this.validateEmail));
this.addDialog(new TextPrompt(ZIP_PROMPT,this.validateZip));
this.addDialog(new ConfirmPrompt(CONFIRM_PROMPT));
this.addDialog(new ChoicePrompt(CHOICE_PROMPT));
this.addDialog(new WaterfallDialog(WATERFALL_DIALOG, [
this.requestOrderNumber.bind(this),
this.selectOrderType.bind(this), // This is being bypassed by current Filtration store implementation
this.selectSearchCriteria.bind(this),
this.getQueryData.bind(this),
this.confirmBillingZip.bind(this),
this.confirmBillingEmail.bind(this),
this.displayLineStatus.bind(this),
this.getEmailAddress.bind(this),
this.setFollowUp.bind(this),
this.loopStep.bind(this)
]));
this.initialDialogId = WATERFALL_DIALOG;
this.queryData = {};
// State accessors
this.userDialogStateAccessor = userDialogStateAccessor;
this.userState = userState;
this.dialogState = dialogState;
this.conversationState = conversationState;
this.appInsightsClient = appInsightsClient;
this.addDialog(new PaginateDialog(PAGINATE_DIALOG, this.userDialogStateAccessor, userState, this.appInsightsClient));
// Luis Recognizer
this.luisRecognizer = new LuisRecognizer({
applicationId: process.env.LuisAppId,
endpointKey: process.env.LuisAPIKey,
endpoint: `https://${ process.env.LuisAPIHostName }`
}, {
includeAllIntents: true,
includeInstanceData: true,
spellCheck: true,
bingSpellCheckSubscriptionKey: process.env.bingAPIKey
}, true);
} // End constructor
@Arie Rodrigues got me going in the right direction but the solution was not quite correct. Bot Framework does in fact seem to be using a single instance of the dialog, with it being controlled by the conversation/dialog state. So the this.queryData
object defined in the constructor was actually being shared by all dialogs. With the right timing, prompt inputs were crossing from one user's dialog to the other.
This could be solved with any method to save these values non-globally. Conversation state would be a good one, but I didn't need or want to save the values for the duration of the conversation nor mess with retrieving and saving the state every step. Instead, I used step.values
in place of this.queryData
. My code had actually relied on some values of this.queryData
being persisted when the dialog was looped at a certain step via replaceDialog()
, so I had to make sure to pass those in the options of that method. This seems to have fixed the issue, as I had 4 testers hitting the same dialogs at the same time with different prompt values without issue.