microsoft / botframework-components

The repository for components built by Microsoft for the Azure Bot Framework.
https://aka.ms/botdocs
MIT License
113 stars 82 forks source link

"The CancellationTokenSource has been disposed" error in Teams when using Microsoft.Bot.Components.Recognizers.CustomQuestionAnsweringRecognizer #1489

Open DanielHjelm opened 1 year ago

DanielHjelm commented 1 year ago

I am using Microsoft.Bot.Components.Recognizers.CustomQuestionAnsweringRecognizer for enabling my CQA resource in my Bot built-in Bot Composer. When I publish a new version of the bot to Azure Bot Service, my bot stops answering and I get the error "The CancellationTokenSource has been disposed". I have debugged and found out that it is indeed when CQA dialog that is causing this problem. Here is the entire error code:

Exception: System.ObjectDisposedException: The CancellationTokenSource has been disposed.    at System.Threading.CancellationTokenSource.ThrowObjectDisposedException()    at System.Threading.CancellationTokenSource.Cancel()    at Microsoft.Bot.Builder.ShowTypingMiddleware.FinishTypingTaskAsync(ITurnContext turnContext)    at Microsoft.Bot.Builder.ShowTypingMiddleware.b4_0(ITurnContext ctx, List1 activities, Func1 nextSend)    at Microsoft.Bot.Builder.TelemetryLoggerMiddleware.<>c__DisplayClass7_0.<b0>d.MoveNext() --- End of stack trace from previous location where exception was thrown ---    at Microsoft.Bot.Builder.TurnContext.SendActivityAsync(IActivity activity, CancellationToken cancellationToken)    at Microsoft.Bot.Builder.TurnContext.SendActivityAsync(String textReplyToSend, String speak, String inputHint, CancellationToken cancellationToken)    at Microsoft.Bot.Builder.Dialogs.Adaptive.Runtime.CoreBotAdapter.<.ctor>b0_0(ITurnContext turnContext, Exception exception)    at Microsoft.Bot.Builder.BotAdapter.RunPipelineAsync(ITurnContext turnContext, BotCallbackHandler callback, CancellationToken cancellationToken)    at Microsoft.Bot.Builder.CloudAdapterBase.ProcessActivityAsync(AuthenticateRequestResult authenticateRequestResult, Activity activity, BotCallbackHandler callback, CancellationToken cancellationToken)    at Microsoft.Bot.Builder.CloudAdapterBase.ProcessActivityAsync(String authHeader, Activity activity, BotCallbackHandler callback, CancellationToken cancellationToken)    at Microsoft.Bot.Builder.Integration.AspNet.Core.CloudAdapter.ProcessAsync(HttpRequest httpRequest, HttpResponse httpResponse, IBot bot, CancellationToken cancellationToken)    at Bot.Controllers.BotController.PostAsync(String route) in /Users/danielhjelm/Desktop/ChatBot/Bot/Bot/Controllers/BotController.cs:line 67    at lambda_method(Closure , Object )    at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()    at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)    at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.gLogged|12_1(ControllerActionInvoker invoker)    at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.gAwaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)    at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)    at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)    at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.gAwaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)    at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged|17_1(ResourceInvoker invoker)    at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)    at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)    at Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware.Invoke(HttpContext httpContext)    at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

ramfattah commented 1 year ago

Thanks for reporting this issue @DanielHjelm. I'm investigating.

ramfattah commented 1 year ago

Hi @DanielHjelm, thanks for your patience.

I'm not able to reproduce this issue.

After installing and configuring the CustomQuestionAnswering recognizer package in a C# Composer Bot and deployed to Azure App Service (Windows OS), the bot seems to respond the answers as expected from CQA.

Sharing the steps I took:

  1. Created a custom question answering project in Language Studio. (Documentation)
  2. Added the following .pdf source to the Custom question answering project:
  3. Created a C# Composer bot and installed CustomQuestionAnswering package in Composer's package manager tab
  4. Followed the Custom Question Answering Recognizer README.md to configure the recognizer in the composer bot dialog
  5. In the same dialog that CQA is configured, I added a QnA Intent recognized trigger: image
  6. Published the bot to Azure using Composer's built-in publish profile
  7. After Publishing is successful, I added a MSFT Teams channel an open the bot in Teams
  8. The bot responds the same in Teams as in CQA after Composer bot is deployed to Azure image image
ramfattah commented 1 year ago

Hey @DanielHjelm, asking few clarifying questions:

  1. What version of the Bot Builder are you using in Composer and are all the Bot builder version the same?
    • Example, you can check this in Composer's package manager or inside the composer's bot .csproj: Composer: Image from Gyazo
  2. Were you able to successfully publish and communicate with the bot in the past and now suddenly facing this issue?
DanielHjelm commented 1 year ago

Hey @ramfattah! Thanks for taking a look at this!

I found out why this happens but can't find a solution. So what happens is that I use the ConversationUpdate Activity to start the QA dialog (called SolveProblem dialog in the attached image) but then when I publish a new version to the cloud, this activity is not triggered since Teams only sends this ConversationUpdate activity only once when the bot is first installed for the user. As a result, the user is stuck in the "root" dialog where I use LUIS as a recognizer and not CQA.

So my question is, how can I ensure the user is redirected to the SolveProblem dialog when I publish to Teams? I can't set it as the root dialog because then I can't make the LUIS recognizer interrupt and start workflows which is why I designed it in this way from the start.

Screenshot 2023-04-22 at 11 37 26
ramfattah commented 1 year ago

Thanks for the update and detail explanation @DanielHjelm.

Initially, I tested with QnA Intent Recognizer inside the root dialog. I can try to use the ConversationUpdate Activity to start a QA dialog to see if it reproduces the same behavior.

Will report back soon.

DanielHjelm commented 1 year ago

Have you got any updates @ramfattah?

DanielHjelm commented 1 year ago

@ramfattah

ramfattah commented 1 year ago

Hey @DanielHjelm,

Thanks for your patience. This issue is being actively investigated.

Will provide an update soon. Thanks.

ramfattah commented 1 year ago

Hey @DanielHjelm,

Sharing a brief explanation of this issue as so we are all on the same page. Please correct me if I misunderstood.

  1. In root dialog, there is a Greeting (ConversationUpdate activity) trigger
  2. This Greeting (ConversationUpdate activity) sends the user to another dialog that contains a QnA Intent recognizer which uses the CustomQuestionAnswering recognizer Example: image
  3. This set up works initially when user's install the bot in Teams, but after re-deploying a new version of the bot, since the bot app is already installed in Teams, the Greeting (ConversationUpdate activity) is not being triggered and user is stuck in root dialog

#

So my question is, how can I ensure the user is redirected to the SolveProblem dialog when I publish to Teams?

Is the goal to automatically send the user to a different dialog that uses CustomQuestionAnswering recognizer but still have LUIS recognizer in root dialog?

DanielHjelm commented 1 year ago

Hi @ramfattah,

Yes, that is precisely what my problem is and what I am trying to achieve!

As I mentioned above, I can't set the CustomQuestionAnswering recognizer dialog as the root dialog since then I can't make the LUIS recognizer interrupt and start workflows. Do you have any other suggestions on how I can solve this? As you and I mentioned above, this is only a problem when I re-publish a new version of the bot to Teams since then the Greeting (ConversationUpdate activity) is not triggered. Is there any other trigger I can use to make sure the user ends up in the CustomQuestionAnswering dialog? Or this any other way I can design my bot to have similar functionality as it has right now?

ramfattah commented 1 year ago

Hey @DanielHjelm,

I'm not able to reproduce this error message: "The CancellationTokenSource has been disposed"

After re-deploying the bot to Azure when the bot is already installed and going to the bot chat in Teams, it just doesn't go into the SolveProblemDialog as the ConversationUpdate activity is not triggered.

Are you able to provide the steps to reproduce the CancellationTokenSource error message?

Attached is the Composer bot sample I used for testing: https://1drv.ms/u/s!AhLP1QfVMeI1rQDDyRrg9ARQraiD?e=Kade3X

ComposerBot.zip
Compressed (zipped) Folder
DanielHjelm commented 1 year ago

Hi @ramfattah,

I can actually not reproduce the steps right now either and I don't know why. Now it just doesn't answer because it doesn't go into the SolveProblemDialog as the ConversationUpdate activity is not triggered. But the procedures I did to produce the error were:

  1. Publish the bot to Azure through Composer
  2. Remove the conversation with the bot in Teams (since it did not answer as the ConversationUpdate activity was not triggered)
  3. Send a message to the bot that should've been answered by SolveProblemDialog

By following these steps the bot sent back a message saying "The CancellationTokenSource has been disposed" and I looked at the logs to see the entire error message.

Please answer the questions I stated in my previous message. Thanks!

ramfattah commented 1 year ago

Hi @DanielHjelm,

I'm discussing this internally to see if this scenario is supported.

#

Please answer the questions I stated in my previous message. Thanks!

I'm not quite sure, still looking into this. I have not designed a bot where after re-deployment of the bot, it would then in Teams automatically send the user to a different dialog that uses CustomQuestionAnswering recognizer but still have LUIS recognizer in root dialog.

A potential workaround we have in mind involves utilizing the LUIS recognizer in the root dialog to redirect to the CustomQuestionAnswering dialog. In this scenario, after the bot is re-deployed, the user could enter 'cqa' or another designated phrase in the root LUIS recognizer dialog, which would then redirect them to the SolveProblem (CQA) dialog. Does this alternative approach seem acceptable?

DanielHjelm commented 1 year ago

Hi again @ramfattah,

Thanks for looking into this!

I've already managed to solve this problem with a similar approach as you explained above. However, ideally, I would want the user to be directly redirected to the CustomQuestionAnswering recognizer when the code is re-published or when the user writes the first time after re-publishment and not having to write something like "cqa".

DanielHjelm commented 1 year ago

@ramfattah Any other suggestions on how to do this?