Développement d’un robot – gérer la limite de requêtes sur API tierce avec Azure Table Storage

Pour le développement de mon robot, j’ai dû gérer une limite de requête sur l’API qui me permet 2000 appels par mois.

J’ai donc implémenté une solution qui utilise Azure Table Storage pour stocker la date de dernière requête effectuée et le nombre d’appels utilisés.

J’ai tout d’abord créé un compte de stockage pour mon application en me connectant au portail Azure.

Puis j’ai installé Azure Storage Explorer, formidable outil pour gérer ses ressources de stockage sur le cloud Azure.

Ensuite, j’ai créé la table qui va servir à stocker mes données pour limiter les appels à l’API.

Dans cette table, je dois fournir 2 champs qui définissent la clé unique d’un enregistrement, Dans “PartitionKey”, j’ai indiqué le nom du fournisseur de l’API et dans “RowKey”, j’ai indiqué le nom de l’application qui initie les appels. J’ai ajouté 2 champs, un qui stocke la date du dernier appel à l’API et l’autre pour stocker le nombre d’appels effectués dans le mois en cours.

C’est tout pour la partie stockage dans le cloud.

Dans le code de mon robot, j’ai créé une classe qui correspond à la table Azure

Puis, j’ai créé une classe “RequestLimiter” qui va accéder à Azure, lire les données de la table et les modifier.

using Microsoft.WindowsAzure.Storage.Table;
using System;
 
namespace FinancialAdvisor.Entity
{
    public class RequestLimitEntity : TableEntity
    {
        public RequestLimitEntity(string Provider, string AppName)
        {
            this.PartitionKey = Provider;
            this.RowKey = AppName;
        }
 
        public RequestLimitEntity() { }
 
        public DateTime LastQueryDate{ get; set; }
 
        public Int32 QueriesNumber { get; set; }
    }
}
using Microsoft.Azure;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using System;
 
namespace FinancialAdvisor.Entity
{
    public class RequestLimiter : IRequestLimiter
    {      
        private CloudTableClient tableClient;
        private CloudTable table;
 
        public RequestLimiter()
        {
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
                CloudConfigurationManager.GetSetting("StorageConnectionString"));
            TableClient = storageAccount.CreateCloudTableClient();
        }
 
        public CloudTableClient TableClient { get => tableClient; set => tableClient = value; }
 
        public RequestLimitEntity Read()
        {
            table = TableClient.GetTableReference("RequestLimit");
            TableOperation tableOperation = TableOperation.Retrieve<RequestLimitEntity>("MonFournisseur", "FinancialAdvisor");
            TableResult retrievedResult = table.Execute(tableOperation);
            return (RequestLimitEntity)retrievedResult.Result;
        }
 
        public void Update(RequestLimitEntity entity, DateTime RequestDatetime, Int32 QueriesNumber)
        {
            if (entity != null)
            {
                entity.LastQueryDate = RequestDatetime;
                entity.QueriesNumber = QueriesNumber;
                TableOperation updateOperation = TableOperation.Replace(entity);              
                table.Execute(updateOperation);
            }
        }
    }
}

Dans le code de cette classe, on voit dans le constructeur que je me connecte à Azure avec la chaîne de connexion stockée dans le web.config.

La méthode “Read” me permet de lire l’enregistrement correspondant à la clé composite sur la PartitionKey et RowKey.

La méthode “Update” met à jour l’enregistrement avec la date de la requête qui vient d’être effectuée et le nombre que j’ai incrémenté.

J’extrais l’interface de cette classe afin de l’utiliser avec AutoFac.

using System;
using Microsoft.WindowsAzure.Storage.Table;
 
namespace FinancialAdvisor.Entity
{
    public interface IRequestLimiter
    {
        CloudTableClient TableClient { get; set; }
 
        RequestLimitEntity Read();
        void Update(RequestLimitEntity entity, DateTime RequestDatetime, int QueriesNumber);
    }
}

En effet, les objets qui sont instanciés dans une classe utilisée par le Bot Framework doivent être marquées comme [Serializable].

Pour éviter de marquer toutes les classes, on peut utiliser AutoFac en obtenant une référence d’objet par inversion de contrôle.

De la sorte, je peux utiliser mon objet _requestLimiter dans la classe d’appel à mon API.

public string ExecQuery(string query)
        {
            IRequestLimiter _requestLimiter = ServiceResolver.Get<IRequestLimiter>();
                RequestLimitEntity entity = _requestLimiter.Read();
 
            if (entity.LastQueryDate.Month == DateTime.Now.Month && entity.QueriesNumber == 2000)
                return "No more queries available for this month, sorry";
 
            if (DateTime.Now.Month > entity.LastQueryDate.Month)
                _requestLimiter.Update(entity, DateTime.Now, 1);
...

On lit dans le code que j’utilise mon objet _requestLimiter tout d’abord pour lire le contenu de la table. Puis, je regarde si j’ai atteint la limite mensuelle, dans ce cas j’informe l’utilisateur. Ensuite, si je détecte que je viens de changer de mois, j’update ma table en indiquant 1 comme nombre de requêtes.C#

_requestLimiter.Update(entity, DateTime.Now, entity.QueriesNumber + 1);

Plus loin dans le code, après avoir exécuté un nouvel appel à l’API, j’incrémente le nombre de requêtes utilisées.

Et voilà! il existe des améliorations possibles comme stocker le nombre maximum d’appels autorisés, ou la base de référence des appels (mensuelle, quotidienne, etc).


January 1, 2018

Tags: ,

Leave a Reply

Your email address will not be published. Required fields are marked *