2
votes

Azure fonctions host.json ignorées d'une manière ou d'une autre

J'ai une fonction Azure V2. J'ai configuré cette fonction pour n'exécuter qu'une seule fonction en parallèle. Ceci est mon fichier host.json:

{ "version": "2.0", "extensions": { "files d'attente": { "batchSize": 1, "newBatchThreshold": 0 } } }

Lorsque je lance la fonction sur ma machine de développement locale, elle affiche la sortie suivante:

[27-5-2019 12:43:06] Démarrage du service d'initialisation Rpc.

[27-5-2019 12:43:06] Initialisation de RpcServer

[27-5-2019 12:43:06] Hôte du bâtiment: démarrage supprimé: False, configuration supprimé: Faux

[27-5-2019 12:43:07] Initialisation de l'hôte.

[27-5-2019 12:43:07] Initialisation de l'hôte: ConsecutiveErrors = 0, StartupCount = 1

...

[27-5-2019 12:43:07] QueuesOptions

[27-5-2019 12:43:07] {

[27-5-2019 12:43:07] "BatchSize": 16,

[27-5-2019 12:43:07] "NewBatchThreshold": 8,

[27-5-2019 12:43:07] "MaxPollingInterval": "00:00:02",

[27-5-2019 12:43:07] "MaxDequeueCount": 5, **

[27-5-2019 12:43:07] "VisibilityTimeout": "00:00:00"

Suite à cette sortie, il semble ne pas avoir enregistré ces paramètres. Le comportement montre également cela car la fonction s'exécute en parallèle au lieu d'une à la fois. Qu'est-ce que je fais mal?

Toute aide est appréciée.

Référence à la spécification


2 commentaires

Utilisez-vous le plan Azure App Service ou le plan de consommation?


Plan de consommation, mais cet exemple vient de le frotter en développement.


4 Réponses :


4
votes

On dirait un problème ouvert signalé ici , Fonctions de démarrage ignorées host.json

Si vous avez [assembly: WebJobsStartup (typeof (Startup))] dans votre code, supprimer cela devrait reconnaître correctement host.json .


1 commentaires

Cela signifie donc que nous n'avons pas de DI ou pas de host.json, ce n'est pas la meilleure situation. Je vais marquer cela comme la réponse pour le moment, car il n'y a pas d'alternative valide



3
votes

J'ai répondu au même problème (ou similaire) signalé dans github. Pour aider les autres à atterrir ici, je publie à nouveau ici.


Ajout d'un peu plus d'informations pour les autres qui atterrissent ici. De plus, comme je n'ai vu personne d'autre mentionner cela, je peux interpréter / faire mal. Si tel est le cas, veuillez en parler.

Scénario

  • Fonctions de l'application v2, SDK 1.0.29
  • C #
  • en utilisant [assembly: FunctionsStartup (typeof (Startup))]
  • Utilisation de new ConfigurationBuilder () , ajout de mes éléments de configuration
  • Enregistrement de IConfigurationRoot construit comme singleton IConfiguration

Ce que j'ai observé

Définition d'un point d'arrêt avant d'ajouter mon IConfigurationRoot et de consulter le code IServiceCollection > Je pouvais voir qu'il y avait déjà un singleton IConfiguration enregistré. De plus, cette instance contenait le fournisseur host.json, mais il n'était pas chargé lors de l'exécution dans Azure.

Ma théorie

Il semble que lorsque deux singletons du même service sont enregistrés, le framework DI va simplement récupérer le dernier ajouté.

Ma solution

J'ai extrait le IConfiguration du fournisseur IServiceCollection et l'ajouté au ConfigurationBuilder afin que ses valeurs soient incluses dans le ConfigurationRoot que j'enregistre et est donc saisi par le framework DI.

Code

public IConfigurationRoot AddSettings(IServiceCollection services, string basePath, string name, bool optional, bool reloadOnChange)
{
    var builder = new ConfigurationBuilder().SetBasePath(basePath);

    var existingConfigs = services.Where(svc => svc.ServiceType.Name == "IConfiguration").ToList();
    foreach (var cfg in existingConfigs)
        builder.AddConfiguration((IConfigurationRoot) cfg.ImplementationInstance);

    // Register/load the requested json settings file
    builder.AddJsonFile(name, optional, reloadOnChange);

    // Add all environment vars and build the ConfigurationRoot object. Then register it with the services container
    builder.AddEnvironmentVariables();
    var config = builder.Build();

    // Register the resulting IConfigurationRoot to as a singleton
    services.AddSingleton<IConfiguration>(config);

    return config;
}

J'espère que cela sera utile à quelqu'un


2 commentaires

L'idée est là, je pense, mais cela ne fonctionne pas pour moi. Peut-être que je n'appelle pas cette méthode correctement? Je passe le builder.Services comme premier argument. Ce générateur est un IFunctionsHostBuilder . Mais alors, cfg.ImplementationInstance est nul. D'autres astuces?


J'ai fatigué service.Replace dans la v3 mais cela ne fonctionne pas bien que HostJsonProvider soit présent dans les sources de configuration



5
votes

J'avais exactement le même problème que Dave Parker et son analyse d'un nouvel enregistrement de configuration écrasant la configuration host.json était parfaite.

Comme jsgoupil l'a commenté sur le message de Dave, ImplementationInstance est nul cependant. Voici quelques légères mises à jour du code de Dave pour gérer cela.

public IConfigurationRoot AddSettings(IServiceCollection services, string basePath, string name, bool optional, bool reloadOnChange)
{
    var builder = new ConfigurationBuilder().SetBasePath(basePath);

    // check if an IConfiguration has already been registered
    var existingConfig = builder.Services.FirstOrDefault(x => x.ServiceType.Name == nameof(IConfiguration));
    if(existingConfig != null)
    {
        // get an instance of it and include it in the new config builder
        var sp = builder.Services.BuildServiceProvider();
        var existingInstance = sp.GetService<IConfiguration>();
        builder.AddConfiguration(existingInstance);
    }

    // Register/load the requested json settings file
    builder.AddJsonFile(name, optional, reloadOnChange);

    // Add all environment vars and build the ConfigurationRoot object. Then register it with the services container
    builder.AddEnvironmentVariables();
    var config = builder.Build();

    // Register the resulting IConfigurationRoot to as a singleton
    services.AddSingleton<IConfiguration>(config);

    return config;
}


2 commentaires

J'ai eu le même problème. La configuration a été perdue car j'ai créé un nouveau ConfigurationBuilder vide, ajouté som json config et l'ai enregistré. L'ajout de la configuration déjà enregistrée par le runtime a fait l'affaire! Merci Nick!


Cela a aidé mon problème. Merci Nick. Je pense que cela devrait être géré par défaut.



0
votes

Merci beaucoup pour cela! J'ai utilisé une petite variation car j'utilise l'invocation différée du modèle d'usine pour référencer la configuration au démarrage:

public static IServiceCollection AddConfigurationFactory(this IServiceCollection services)
{
    var configurationEnvironment = Environment.GetEnvironmentVariable("ConfigEnv");
    var jsonConfigFilename = $"appsettings.{configurationEnvironment}.json";

#if DEBUG
    var basePath = Environment.CurrentDirectory;
#else
    var basePath = @"/home/site/wwwroot";  
#endif
    var existingConfig = services.FirstOrDefault(x => x.ServiceType.Name == 
        nameof(IConfiguration));
    IConfiguration existingInstance = null;
    if (existingConfig != null)
    {
        var spOuter = services.BuildServiceProvider();
        existingInstance = spOuter.GetService<IConfiguration>(); 
    }
    Func<IServiceProvider, IConfiguration> factory = (sp) =>
    {
        var configBuilder = new ConfigurationBuilder()
            .SetBasePath(basePath)
            .AddEnvironmentVariables()
            .AddJsonFile(jsonConfigFilename, optional: false, reloadOnChange: true);
                
        if (existingInstance != null)
            configBuilder.AddConfiguration(existingInstance);

        return configBuilder.Build();
    };
    services.AddSingleton<IConfiguration>(factory);
    return services;
}


0 commentaires