Loupe

WebJob et Azure Functions : utiliser les filters pour détecter les erreurs

Lorsque vous utilisez des WebJobs ou des très puissantes Azure Functions (basées sur ce même SDK), il est assez simple de réagir aux erreurs en suivant la documentation officielle. Le seul HIC c'est que ce n'est en réalité plus du tout disponible depuis plusieurs versions du SDK. Dans cet article nous verrons comment arriver au même résultat.

Par attribut - sans injection de dépendances

La documentation officielle nous indique qu'il suffit de poser un attribut ErrorTriggerAttribute sur notre méthode appelée. Cet attribut n'est plus existant dans le SDK mais l'on peut maintenant créer notre propre attribut, ce qui est presque mieux ! Cela n'est disponible que pour les fonctions .NET précompilées pour le moment. On peut simplement regretter que cela ne soit pas du tout documenté sur GitHub ou la documentation officielle. 

Pour créer son propre attribut, il faut dériver de la classe FunctionInvocationFilterAttribute

public class ErrorFilterAttribute : FunctionInvocationFilterAttribute
{
    public override Task OnExecutingAsync(
        FunctionExecutingContext executingContext,
        CancellationToken cancellationToken)
    {
        return base.OnExecutingAsync(executingContext, cancellationToken);
    }
    public override Task OnExecutedAsync(
        FunctionExecutedContext executedContext,
        CancellationToken cancellationToken)
    {
        if (!executedContext.FunctionResult.Succeeded)
        {
            Debug.WriteLine(
                "vilaine exception : "
                + executedContext.FunctionResult.Exception);
        }
        return base.OnExecutedAsync(executedContext, cancellationToken);
    }
}

Les différentes méthodes disponibles à la surcharge sont alors appelées après ou avant l'exécution de notre code. Il est alors possible de savoir son résultat (échec ou succès) et même l'exception ayant produit l'échec.

Cet attribut peut alors être posé sur chaque méthode correspondant à une fonction, un webjob ou sur la classe les définissants : 

[ErrorFilter]
public async Task RunOnTimeTriggeredAsync(
    [TimerTrigger("%" + ImportConfiguration.SheduleKey+ "%")]
    TimerInfo myTimer,
    ILogger logger)
{
...
}

Par injection

Le défaut de la méthode précédente est qu'il n'est pas possible de se faire injecter un service dans notre filtre. Il est possible de palier à ce défaut en créant une classe implémentant IFunctionInvocationFilter et en l'injectant dans le système de DI du worker au démarrage (expliqué en anglais ici). Il ne sera cependant plus possible de ne cibler qu'une seule méthode de votre projet WebJob ou d'Azure Functions.

Le code reste très similaire :

public class ErrorInvocationFilter : IFunctionInvocationFilter
{
    private readonly IMyService _myService
    public ErrorInvocationFilter(IMyService myService)
    {
        _myService = myService;
    }
    public Task OnExecutingAsync(
        FunctionExecutingContext executingContext,
        CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }
    public Task OnExecutedAsync(
        FunctionExecutedContext executedContext,
        CancellationToken cancellationToken)
    {
        if (!executedContext.FunctionResult.Succeeded)
        {
            Debug.WriteLine(
                "vilaine exception : "
                + executedContext.FunctionResult.Exception);
        }
        return Task.CompletedTask;
    }
}

L'enregistrement se fait de manière classique : 

#pragma warning disable 618
services.AddSingleton<IFunctionFilter, ErrorInvocationFilter>();
#pragma warning restore 618

Si vous ne souhaitez gérer que les exceptions, il existe aussi l'interface IFunctionExceptionFilter.

Happy coding :)

Photo de profil

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus