Контекстное ожидание случайным образом завершается ошибкой / Один и тот же «метод ожидания» вызывается два раза подряд - PullRequest
0 голосов
/ 26 июня 2018

мы разработали BOT с использованием Microsoft Bot Framework 3.0 с некоторым диалогом, связывающим друг друга с Context.Wait (Метод). Каждый публикует сообщение и устанавливает другой метод диалога в ожидании следующего сообщения.

Пример кода

Наш контроллер сообщений:

    public async Task<HttpResponseMessage> Post([FromBody]Activity activity)
    {
        if (activity.GetActivityType() == ActivityTypes.ConversationUpdate)
        {
            if (activity.MembersAdded.Any(m => m.Id != activity.Recipient.Id))
            {
                activity.Type = ActivityTypes.Message;
                activity.Text = _startGreetingsMessage;
            }
        }

        if (activity.GetActivityType() == ActivityTypes.Message)
        {
            using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity))
            {
                var dialog = scope.Resolve<IDialog<object>>();
                await Conversation.SendAsync(activity, () => dialog);
            }
        }
        else
        {
            HandleSystemMessage(activity);
        }

        var response = Request.CreateResponse(HttpStatusCode.Accepted);
        return response;
    }

Наш RootDialog наследует от Луиса:

[Serializable]
public class RootDialog : LuisDialog<object>
{
    private readonly IDialogFactory _dialogFactory;

    public RootDialog(ILuisService luisService, IDialogFactory dialogFactory)
        : base(luisService)
    {
        _dialogFactory = dialogFactory;
    }

    [LuisIntent("None")]
    public async Task NoneIntent(IDialogContext context, LuisResult result)
    {
         await context.PostAsync(MessagesResource.CourtesyError);
         context.Call(_dialogFactory.Create<GreetingDialog>(), Callback);
    }

    [LuisIntent("Greetings")]
    public async Task GreetingsIntent(IDialogContext context, LuisResult result)
    {
        context.Call(_dialogFactory.Create<GreetingDialog>(), Callback);
    }

    [LuisIntent("CreateNewList")]
    public async Task CreateNewListIntent(IDialogContext context, LuisResult result)
    {
        context.Call(_dialogFactory.Create<CreateNewShoppingListDialog>(), Callback);
    }

    [LuisIntent("OpenLastList")]
    public async Task OpenLastListIntent(IDialogContext context, LuisResult result)
    {
        context.Call(_dialogFactory.Create<OpenLastShoppingListDialog>(), Callback);
    }

    [LuisIntent("GetTimetables")]
    public async Task GetTimetablesIntent(IDialogContext context, LuisResult result)
    {
        context.Call(_dialogFactory.Create<OpeningHoursDialog>(), Callback);
    }

    [LuisIntent("GetPromo")]
    public async Task GetPromoIntent(IDialogContext context, LuisResult result)
    {
        context.Call(_dialogFactory.Create<PromoProductsByCategoryDialog>(), Callback);
    }

    [LuisIntent("")]
    public async Task CancelIntent(IDialogContext context, LuisResult result)
    {
        await context.PostAsync(MessagesResource.CourtesyError);
        context.Call(_dialogFactory.Create<GreetingDialog>(), Callback);
    }

    private async Task Callback(IDialogContext context, IAwaitable<object> result)
    {
        await result;
        context.Done(true);
    }
}

Пример того, как мы видим время ожидания между частями диалога:

[Serializable]
public class AskIfAddAnotherProductTask
{
    private readonly IShoppingListsService _shoppingListsService;
    private readonly IDialogFactory _dialogFactory;
    private readonly ILogger _logger;

    public AskIfAddAnotherProductTask(IDialogFactory dialogFactory, IShoppingListsService shoppingListsService, ILogger logger)
    {
        _shoppingListsService = shoppingListsService;
        _dialogFactory = dialogFactory;
        _logger = logger;
    }
    public async Task GetTask(IDialogContext context, IAwaitable<IMessageActivity> result)
    {
        var userResponse = await result;
        var channel = context.Activity.ChannelId;

        var dict = new Dictionary<string, object>() { { "context", context } };

        var luisResult = await LuisHelper.GetIntentAndEntitiesFromLUIS(userResponse.Text);

        switch (luisResult.TopScoringIntent.Intent)
        {
            case LuisIntent.Yes:
                {
                    await context.PostAsync(MessagesResource.AddOtherProducts);
                    context.Wait(_dialogFactory.Create<GetProductsByUserTask>().GetTask);
                    break;
                }
            case LuisIntent.No:
                {
                    var sender = _dialogFactory.Create<SendCorrectYesOrNoCard>(dict);
                    await sender.Send(channel, MessagesResource.AskIfWantSuggestions);

                    var handler = _dialogFactory.Create<HandleUserIncorrectInput>(dict);
                    handler.ResetCounter();

                    context.Wait(_dialogFactory.Create<AskIfWantSuggestionProductsTask>().GetTask);
                    break;
                }
            default:
                {
                    await context.PostAsync(MessagesResource.CourtesyChooseError);

                    var sender = _dialogFactory.Create<SendCorrectYesOrNoCard>(dict);

                    await sender.Send(channel, MessagesResource.AskIfWantAddProduct);

                    context.Wait(GetTask);
                    break;
                }
        }
    }
}

Этапы воспроизведения

Это случайно, особого шага для воспроизведения нет. Мы столкнулись с проблемой на канале мессенджера Facebook.

Ожидаемое поведение

Всегда вызывайте правильный метод: -)

Фактические результаты

Иногда, случайно, мы сталкивались с тем, что один и тот же «метод в ожидании» вызывается два раза подряд ... что-то не получается при последней вставке метода в ожидании или что-то в этом роде ... , У кого-нибудь есть идеи по этому поводу? Мы опробовали несколько вариантов и обойти безуспешно ...

UPDATE:

В основном у нас такая ситуация: RootDialog -> context.call (DialogA, RootDialogCallback) -> context.wait ( MethodFromAnotherClass1 ) .... -> context.wait ( MethodFromAnotherClassN ) -> context.done () -> RootDialogCallback -> context.done ()

Это работает примерно в 70-80% случаев ... Так что мой вопрос это: правильно связать метод из разных классов с Context.Wait или такой подход может привести к некоторой случайной проблеме как тот, который мы переживаем?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...