1
votes

I have a bot with a root LuisDialog and 4 more LuisDialogs each one with a different LUIS model. Following the conversation started here I've implemented a similar DialogFactory strategy.

When a user sends a question that matches "None" intent in my root dialog, I evaluate the rest of dialogs until I find a match and then forward the message to the "winner".

The problem I'm facing is that I'm getting the http error: 429 (Too Many Requests) when querying LUIS (BaseDialog class).

Any ideas about how to face this?

The "None" intent in my root dialog:

    [LuisIntent("None")]
public async Task None(IDialogContext context, IAwaitable<IMessageActivity> message, LuisResult result)
{
    var activity = await message;

    var factory = new DialogFactory();
    BaseDialog<object> dialog = await factory.Create(result.Query);
    if (dialog != null)
    {
        await context.Forward(dialog, EndDialog, activity, CancellationToken.None);
    }
    else
    {
        await context.PostAsync("No results!");
    }
}

public static async Task EndDialog(IDialogContext context, IAwaitable<object> result)
{
    //...
}

The DialogFactory class:

    using System;
using System.Collections.Generic;
using System.Configuration;
using System.Threading.Tasks;

namespace CodeBot.Dialogs
{
    public class DialogFactory
    {
        private static object _lock = new object();
        private static List<BaseDialog<object>> Dialogs { get; set; }

        public async Task<BaseDialog<object>> Create(string query)
        {
            query = query.ToLowerInvariant();
            EnsureDialogs();
            foreach (var dialog in Dialogs)
            {
                if (await dialog.CanHandle(query))
                {
                    return dialog;
                }
            }
            return null;
        }

        private void EnsureDialogs()
        {
            if (Dialogs == null || (Dialogs.Count != 4))
            {
                lock (_lock)
                {
                    if (Dialogs == null)
                    {
                        Dialogs = new List<BaseDialog<object>>();
                    }
                    else if (Dialogs.Count != 4)
                    {
                        Dialogs.Clear();
                    }

                    Dialogs.Add((BaseDialog<object>)Activator.CreateInstance(typeof(Dialog1));
                    Dialogs.Add((BaseDialog<object>)Activator.CreateInstance(typeof(Dialog2));
                    Dialogs.Add((BaseDialog<object>)Activator.CreateInstance(typeof(Dialog3));
                    Dialogs.Add((BaseDialog<object>)Activator.CreateInstance(typeof(Dialog4));
                }
            }
        }
    }
}

And finally, the BaseDialog class (where I'm getting the error):

    using Microsoft.Bot.Builder.Dialogs;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Luis;
using System;

namespace CodeBot.Dialogs
{
    [Serializable]
    public class BaseDialog<R> : LuisDialog<R>
    {
        public LuisModelAttribute Luis_Model { get; private set; }

        public BaseDialog(LuisModelAttribute luisModel) : base(new LuisService(luisModel))
        {
            Luis_Model = luisModel;
        }

        public async Task<bool> CanHandle(string query)
        {
            try
            {
                var tasks = services.Select(s => s.QueryAsync(query, CancellationToken.None)).ToArray();
                var results = await Task.WhenAll(tasks);  <-- Error!!!

                var winners = from result in results.Select((value, index) => new { value, index })
                              let resultWinner = BestIntentFrom(result.value)
                              where resultWinner != null
                              select new LuisServiceResult(result.value, resultWinner, this.services[result.index]);

                var winner = this.BestResultFrom(winners);

                return winner != null && !winner.BestIntent.Intent.Equals(Constants.NONE, StringComparison.InvariantCultureIgnoreCase);
            }
            catch(Exception e)
            {
                System.Diagnostics.Debug.WriteLine($"CanHandle error: {e.Message}");
                return false;
            }
        }
    }
}
1

1 Answers

1
votes

The 429 error is caused by your application (key) hitting the LUIS API too heavily.

You need to either throttle your requests to ensure you stay below the threshold of the free tier, or upgrade to the Basic plan which allows 50 requests a second.