howdyai / botkit

Botkit is an open source developer tool for building chat bots, apps and custom integrations for major messaging platforms.
MIT License
11.38k stars 2.29k forks source link

Conversation become "duplicated" when running long operation #2219

Closed cplanson closed 2 years ago

cplanson commented 2 years ago

Hi,

Are you sure this is an issue with the Botkit core module?

Yes

What are you trying to achieve or the steps to reproduce?

We're trying to create a simple conversation using BotkitConversation. The conversation includes a confirmation question. If the user confirms it triggers a somewhat "long running" operation (more than 3 seconds). But then botkit triggers the handler twice. I reproduced the error using a simple setTimeout, and the threshold to reproduce the issue seems to be around 3 seconds :

const slackConfig: SlackAdapter = new SlackAdapter({
    botToken: process.env.slackToken,
    clientSecret: process.env.clientSecret,
    clientId: process.env.clientId,
    clientSigningSecret: process.env.clientSigningSecret,
});

var controller = new Botkit({
    adapter: slackConfig
});

const conversation = new BotkitConversation('conversation', controller);

conversation.ask('Please confirm (yes/no)', [
    {
        pattern: 'yes',
        handler: async function(answer, convo, bot) {
            await bot.say("You said yes");
            await new Promise(resolve => setTimeout(resolve, 3000));
            await bot.say("end");
        }
    }
],{key: 'convo_confirmation'});

controller.addDialog(conversation);

controller.hears("hello", "message", async function(bot, message) {
    await bot.beginDialog('conversation');  
});

What was the result you received?

When answering 'yes' the corresponding handler is triggered twice, the conversation seems to have been duplicated, all following bot answers are sent twice to slack.

What did you expect?

The handler is triggered only once.

Context:

benbrown commented 2 years ago

This is likely due to the fact that slack will resend messages if you do not respond within a small amount of time.

In order to resolve this, you'll want to return a promise from your handler, and handle the dialog inside the promise. This will allow it to respond to slack quickly.

This requires you to call await bot.changeContext(message.reference) inside the promise.