Gestion des erreurs

Découvrez comment gérer les erreurs et les exceptions.

Des erreurs Java sont générées en tant qu'exceptions lors de la création ou de l'exécution de votre application. La classe NoSQLException est la base de la plupart des exceptions générées par le pilote. Cependant, le pilote génère des exceptions directement pour certaines classes, telles que IllegalArgumentException et NullPointerException.

En général, les instances d'exception NoSQL sont réparties en deux grandes catégories :

  • Exceptions pouvant faire l'objet d'une nouvelle tentative susceptible de réussir.

    Ces exceptions sont des instances de la classe RetryableException. Ces exceptions indiquent généralement des violations de consommation de ressources, telles que ThrottlingException.

  • Exceptions qui échoueront même après une nouvelle tentative.

    Par exemple, IllegalArgumentException et TableNotFoundException font partie des exceptions qui ne doivent pas faire l'objet d'une nouvelle tentative, de même que toute autre exception indiquant une erreur de syntaxe ou de sémantique.

Pour en savoir plus sur ces exceptions et leur gestion, reportez-vous au guide de référence de l'API Java.

Les erreurs Python sont générées en tant qu'exceptions définies dans le cadre de l'API. Il s'agit de toutes les instances de Python RuntimeError. La plupart des exceptions sont des instances de borneo.NoSQLException, qui est une classe de base pour les exceptions générées par le pilote Python.

Les exceptions sont réparties en 2 grandes catégories : exceptions pouvant faire l'objet d'une nouvelle tentative susceptible de réussir. Il s'agit de toutes les instances de borneo.RetryableException. Par exemple, les instances de borneo.ThrottlingException sont générées lorsque les limites de consommation des ressources sont dépassées. Exceptions qui ne doivent pas faire l'objet d'une nouvelle tentative car elles échoueront à nouveau. Exemples : borneo.IllegalArgumentException, borneo.TableNotFoundException, etc.

Les instances borneo.ThrottlingException ne seront jamais générées dans une configuration on-premise car il n'existe aucune limite pertinente.

Les erreurs de kit SDK Go sont signalées comme des valeurs nosqlerr.Error définies dans le cadre de l'API. Les erreurs sont réparties en 2 grandes catégories :
  • Erreurs pouvant faire l'objet d'une nouvelle tentative susceptible de réussir. Il s'agit d'erreurs pouvant faire l'objet d'une nouvelle tentative sur lesquelles l'appel de méthode Error.Retryable() renvoie true. Exemples : nosqlerr.OperationLimitExceeded, nosqlerr.ReadLimitExceeded, nosqlerr.WriteLimitExceeded, qui sont générés lorsque les limites de consommation des ressources sont dépassées.
  • Erreurs qui ne doivent pas faire l'objet d'une nouvelle tentative, car elles échoueront à nouveau. Exemples : nosqlerr.IllegalArgumentError, nosqlerr.TableNotFoundError, etc.

Les méthodes asynchrones de NoSQLClient renvoient Promise en conséquence et, si une erreur se produit, le rejet Promise entraîne cette erreur. Pour les méthodes synchrones telles que les erreurs du constructeur NoSQLClient sont générées en tant qu'exceptions. Toutes les erreurs utilisées par le kit SDK sont des instances de NoSQLError ou de l'une de ses sous-classes. Outre le message d'erreur, la propriété errorCode de chaque erreur est définie sur l'un des codes d'erreur standard définis par l'énumération ErrorCode. errorCode peut être utile pour exécuter une logique conditionnelle en fonction de la nature de l'erreur.

Pour certains codes d'erreur, des sous-classes spécifiques de NoSQLError sont définies, telles que NoSQLArgumentError, NoSQLProtocolError, NoSQLTimeoutError, etc. NoSQLAuthorizationError peut avoir l'un des différents codes d'erreur en fonction de la cause de l'échec de l'autorisation. En outre, la propriété cause des erreurs peut être définie sur l'erreur sous-jacente à l'origine de l'erreur en cours. La cause est facultative et peut être une instance d'erreur qui ne fait pas partie du SDK.

En outre, les codes d'erreur sont répartis en 2 grandes catégories :
  • Erreurs pouvant faire l'objet d'une nouvelle tentative susceptible de réussir. Par exemple, ErrorCode.READ_LIMIT_EXCEEDED et ErrorCode.WRITE_LIMIT_EXCEEDED sont des erreurs de ralentissement (qui sont pertinentes pour l'environnement cloud), ainsi que ErrorCode.NETWORK_ERROR car la plupart des conditions réseau sont temporaires.
  • Erreurs qui ne doivent pas faire l'objet d'une nouvelle tentative, car l'opération échouera probablement à nouveau. Par exemple, ErrorCode.ILLEGAL_ARGUMENT (représenté par NoSQLArgumentError), ErrorCode.TABLE_NOT_FOUND, etc.
Vous pouvez déterminer si NoSQLError peut faire l'objet d'une nouvelle tentative en consultant la propriété retryable. Sa valeur est True pour les erreurs pouvant faire l'objet d'une nouvelle tentative. Elle est False ou non définie pour les erreurs qui ne peuvent pas faire l'objet d'une nouvelle tentative.

Gestionnaire de nouvelles tentatives

Le pilote réessaiera automatiquement les opérations en cas d'erreur pouvant faire l'objet d'une nouvelle tentative. Le gestionnaire de nouvelles tentatives détermine :
  • Si et combien de fois l'opération fera l'objet d'une nouvelle tentative.
  • Durée d'attente avant chaque nouvelle tentative.
RetryHandler est une interface avec 2 propriétés :
  • RetryHandler#doRetry qui détermine si l'opération doit faire l'objet d'une nouvelle tentative en fonction de l'opération, le nombre de nouvelles tentatives effectuées jusqu'à présent et l'erreur s'est produite. Cette propriété est généralement une fonction, mais elle peut également être définie sur boolean false pour désactiver les nouvelles tentatives automatiques.
  • RetryHandler#delay qui détermine la durée d'attente avant chaque nouvelle tentative successive en fonction des mêmes informations que celles fournies à RetryHandler#doRetry. Cette propriété est généralement une fonction, mais elle peut également être définie sur le nombre de millisecondes pour un délai constant.
NoSQLException sert de classe de base pour de nombreuses exceptions générées par le pilote. Toutefois, dans certains cas, le pilote utilise des types d'exception standard tels que :
  • ArgumentException et ses sous-classes telles que ArgumentNullException. Elles sont générées lorsqu'un argument non valide est transmis à une méthode ou lorsqu'une configuration non valide (dans le code ou au format JSON) est transmise pour créer une instance NoSQLClient.
  • TimeoutException est généré lorsqu'une opération émise par NoSQLClient a expiré. Si vous obtenez de nombreuses exceptions de délai d'expiration, vous pouvez essayer d'augmenter les valeurs de délai d'expiration dans NoSQLConfig ou dans l'argument d'options transmis à la méthode NoSQLClient.
  • InvalidOperationException est généré lorsque le service est un état non valide pour effectuer une opération. Elle peut également être générée si la requête a échoué, car son traitement a dépassé la limite de mémoire indiquée dans QueryOptions.MaxMemoryMB ou NoSQLConfig.MaxMemoryMB. Dans ce cas, vous pouvez augmenter la limite de mémoire correspondante. Sinon, vous pouvez réessayer l'opération.
  • InvalidCastException et OverflowException peuvent se produire lorsque vous utilisez des sous-classes de FieldValue et que vous essayez de convertir une valeur dans un type qu'elle ne prend pas en charge ou de convertir une valeur numérique dans un type plus petit entraînant un débordement arithmétique.
  • OperationCanceledException et TaskCanceledException si vous avez émis l'annulation de l'opération démarrée par une méthode NoSQLClient utilisant la commande CancellationToken fournie.
En outre, les exceptions peuvent être réparties en deux grandes catégories :
  • Exceptions pouvant faire l'objet d'une nouvelle tentative susceptible de réussir. En général, il s'agit des sous-classes de RetryableException. Il s'agit notamment des exceptions de ralentissement, ainsi que d'autres exceptions dans lesquelles une ressource est temporairement indisponible. Certaines autres sous-classes de NoSQLException peuvent également faire l'objet d'une nouvelle tentative en fonction des conditions dans lesquelles l'exception s'est produite. En outre, les erreurs liées au réseau peuvent faire l'objet d'une nouvelle tentative car la plupart des conditions du réseau sont temporaires.
  • Exceptions qui ne doivent pas faire l'objet d'une nouvelle tentative car elles échoueront après une nouvelle tentative. Elles incluent des exceptions telles que TableNotFoundException, TableExistsException et d'autres, ainsi que des exceptions standard telles que ArgumentException.
Vous pouvez déterminer si une instance donnée de NoSQLException peut faire l'objet d'une nouvelle tentative en vérifiant sa propriété IsRetryable.

Gestionnaire de nouvelles tentatives

Par défaut, le pilote réessaiera automatiquement les opérations qui ont généré une exception réessayable (voir ci-dessus). Le pilote utilise le gestionnaire de nouvelles tentatives pour contrôler les nouvelles tentatives d'opération. Le gestionnaire de nouvelles tentatives détermine :
  • Si et combien de fois l'opération fera l'objet d'une nouvelle tentative.
  • Durée d'attente avant chaque nouvelle tentative.
Tous les gestionnaires de nouvelle tentative implémentent l'interface IRetryHandler. Cette interface fournit deux méthodes : une pour déterminer si l'opération dans son état actuel doit faire l'objet d'une nouvelle tentative et une autre pour déterminer un délai avant la prochaine tentative. Vous avez le choix entre utiliser le gestionnaire de nouvelles tentatives par défaut ou définir votre propre gestionnaire de nouvelles tentatives en tant que propriété RetryHandler de NoSQLConfig lors de la création de l'instance NoSQLClient.
Remarque

Les nouvelles tentatives ne sont effectuées que pendant la période d'expiration allouée à l'opération et configurée en tant que propriété d'expiration dans NoSQLConfig ou dans les options transmises à la méthode NoSQLClient. Si l'opération ou ses nouvelles tentatives n'ont pas abouti avant que le délai d'expiration soit atteint, TimeoutException est généré.
Par défaut, le pilote utilise la classe NoSQLRetryHandler qui contrôle les retraits en fonction du type d'opération, du type d'exception et du nombre maximal de nouvelles tentatives atteint ou non. Il utilise également un délai d'attente exponentiel pour attendre entre deux tentatives en commençant par un délai de base pré-configuré. Vous pouvez personnaliser les propriétés telles que le nombre maximal de tentatives, le délai de base et d'autres en créant votre propre instance de NoSQLRetryHandler et en la définissant en tant que propriété RetryHandler dans NoSQLConfig. Par exemple :
var client = new NoSQLClient(
    new NoSQLConfig
    {
        Region = .....,
        ...............
        RetryHandler = new NoSQLRetryHandler
        {
            MaxRetryAttempts = 20,
            BaseDelay = TimeSpan.FromSeconds(2)
        }
    });
Si vous n'indiquez pas le gestionnaire de nouvelles tentatives, le pilote utilisera une instance de NoSQLRetryHandler avec des valeurs par défaut pour tous les paramètres. Vous pouvez également choisir de créer votre propre classe de gestionnaire de nouvelles tentatives en implémentant l'interface IRetryHandler . La dernière option consiste à désactiver toutes les tentatives ensemble. Vous pouvez le faire si vous prévoyez de réessayer les opérations au sein de votre application. Pour désactiver les nouvelles tentatives, définissez la propriété RetryHandler de NoSQLConfig sur NoRetries :
var client = new NoSQLClient(
    new NoSQLConfig
    {
        Region = .....,
        ...............
        RetryHandler = NoSQLConfig.NoRetries
    });

Limites de ressources : La programmation dans un environnement limité en ressources peut s'avérer difficile. Les tables ont des limites de débit définies par l'utilisateur et, si une application dépasse ces limites, elle peut être ralentie, ce qui signifie qu'une opération peut échouer avec l'une des exceptions de ralentissement telles que ReadThrottlingException ou WriteThrottlingException. Cela est le plus courant lors de l'utilisation de requêtes, qui peuvent lire beaucoup de données et utiliser très rapidement la capacité. Cela peut également se produire pour les opérations get et put qui s'exécutent dans une boucle stricte.

Même si les erreurs de ralentissement font l'objet d'une nouvelle tentative et que l'utilisation de la commande personnalisée RetryHandler peut permettre un contrôle plus direct sur les nouvelles tentatives, une application ne doit pas compter sur de nouvelles tentatives pour gérer le ralentissement, ce qui entraînera des performances médiocres et une incapacité à utiliser l'ensemble du débit disponible pour la table. La meilleure approche serait d'éviter tout ralentissement par limitation de débit de votre application. Dans ce contexte, des moyens de limitation de débit maintiennent les débits de fonctionnement sous les limites de la table.