2

My bot is based on the bot framework and integrated with many channels, Mainly in the telegram, I am facing this error POST to botName timed out after 15s.. is there any way in the code we can restrict in the code?

Sai
  • 91
  • 1
  • 11

1 Answers1

2

I am experiencing a similar issue. My bot doesn't actually cease to function (I'm honestly not sure if console.log error gets thrown) but I do get the Couldn't send. Retry in the webchat UI.

This solution doesn't fix the issue, but it does provide a workaround. I hope if someone else has a direct solution to the issue, they will share it! What you can do instead though is make the API call asynchronous and send the response via proactive message. You can either explicitly let the user know (as I do in my example below), or if the delay isn't that long, you don't have to say anything.

The conversationReference object is required to make this work. I set up my bot to generate this on every message activity (so, onMessage handler or onTurn where context.activity.type === ActivityTypes.Message if you are using older syntax). I'm saving it in conversation state so that I have access to it throughout the bot. You need to import TurnContext from the botbuilder library. Saving the conversationReference is done simply with

// Save the conversationReference
const conversationData = await this.dialogState.get(context, {});
conversationData.conversationReference = TurnContext.getConversationReference(context.activity);
await this.conversationState.saveChanges(context);

I've put together a sample using a dummy API as follows. Note that I am NOT awaiting the API call. This is what will stop that Couldn't send. Retry message from coming up. If you do not need or want to let the user know there will be a delayed response, you can leave out sendActivity. Also, you could just access the conversation state from this other function you are calling, but you have to pass something either way and it appears I just passed the value instead of the state accessor.

case PROACTIVE_MSG_INTENT:
    await dc.context.sendActivity(`OK, I'll simulate a long-running API call and send a proactive message when it's done.`);
    const conversationData = await this.dialogState.get(context, {});
    apiSimulation.longRunningRequest(conversationData.conversationReference);
    break;

So my function here is obviously a simulated API. You would call your API where I have my await new Promise(resolve => setTimeout(resolve, 30000)); statement. You DO want to await this call, since you'll obviously need the response to send back! But the rest of your bot will continue functioning. Here is my entire sample function.

const { BotFrameworkAdapter } = require('botbuilder');

class apiSimulation {
    static async longRunningRequest(conversationReference) {
        console.log('Starting simulated API');
        await new Promise(resolve => setTimeout(resolve, 30000));
        console.log('Simulated API complete');

        // Set up the adapter and send the message
        try {
            const adapter = new BotFrameworkAdapter({
                appId: process.env.microsoftAppID,
                appPassword: process.env.microsoftAppPassword,
                channelService: process.env.ChannelService,
                openIdMetadata: process.env.BotOpenIdMetadata
            });
            await adapter.continueConversation(conversationReference, async turnContext => {
                await turnContext.sendActivity('This message was sent after a simulated long-running API');
            });
        } catch (error) {
            console.log(error);
        }
    }
}

module.exports.apiSimulation = apiSimulation;

And that should be it! Your bot handler won't be waiting for the API response, so you won't get the message, and your separate function will wait for the response and send via proactive messsage/continueConversation. Note that you do NOT need to set up a separate endpoint for proactive messaging like you do in Proactive Notification Sample on GitHub. I suppose you could call this endpoint from within your bot, but it seemed more efficient to me to just create a new adapter to continue the conversation.

billoverton
  • 2,705
  • 2
  • 9
  • 32