在 dotnet 核心 "the configured user limit (128) on the number of inotify instances has been reached" 中读取 json 文件时出错

Error while reading json file in dotnet core "the configured user limit (128) on the number of inotify instances has been reached"

我有一个控制台应用程序(在 dot net core 1.1 中),它在 cron 调度程序中每 1 分钟调度一次。在应用程序内部调用配置文件。我附上下面的代码。

public static T GetAppConfig<T>(string key, T defaultValue = default(T))
{

    T value = default(T);
    logger.Debug($"Reading App Config {key}");
    try
    {
        var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
        var builder = new ConfigurationBuilder()
            .AddJsonFile($"appsettings.json", true, true)
            .AddJsonFile($"appsettings.{environmentName}.json", true, true)
            .AddEnvironmentVariables();
        var configuration = builder.Build();
        T setting = (T)Convert.ChangeType(configuration[key], typeof(T));
        value = setting;
        if (setting == null)
            value = defaultValue;
    }
    catch (Exception ex)
    {
        logger.Warn(ex, $"An exception occured reading app key {key} default value {defaultValue} applied.");
        value = defaultValue;
    }
    return value;
}

应用程序 运行 一段时间后,此错误出现在我的日志文件 "the configured user limit (128) on the number of inotify instances has been reached" 中。请找到完整的堆栈跟踪。

An exception occured reading app key DeviceId default value  applied.
System.IO.IOException: The configured user limit (128) on the number of inotify instances has been reached.
   at System.IO.FileSystemWatcher.StartRaisingEvents()
   at System.IO.FileSystemWatcher.StartRaisingEventsIfNotDisposed()
   at Microsoft.Extensions.FileProviders.Physical.PhysicalFilesWatcher.CreateFileChangeToken(String filter)
   at Microsoft.Extensions.Primitives.ChangeToken.OnChange(Func`1 changeTokenProducer, Action changeTokenConsumer)
   at Microsoft.Extensions.Configuration.Json.JsonConfigurationSource.Build(IConfigurationBuilder builder)
   at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
   at app.Shared.Utilities.GetAppConfig[T](String key, T defaultValue) in /var/app/source/app/app.Shared/Utilities.cs:line 33
   at System.IO.FileSystemWatcher.StartRaisingEvents()
   at System.IO.FileSystemWatcher.StartRaisingEventsIfNotDisposed()
   at Microsoft.Extensions.FileProviders.Physical.PhysicalFilesWatcher.CreateFileChangeToken(String filter)
   at Microsoft.Extensions.Primitives.ChangeToken.OnChange(Func`1 changeTokenProducer, Action changeTokenConsumer)
   at Microsoft.Extensions.Configuration.Json.JsonConfigurationSource.Build(IConfigurationBuilder builder)
   at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
   at app.Shared.Utilities.GetAppConfig[T](String key, T defaultValue) in /var/app/source/app/app.Shared/Utilities.cs:line 33

请告诉我这段代码有什么问题。

看起来配置会在文件更改时自动重新加载。因此,您应该只在应用程序启动时构建一次配置,然后从中读取。

var builder = new ConfigurationBuilder()
        .AddJsonFile($"appsettings.json", true, true);

您每次访问设置时都在创建文件观察器。第三个参数是reloadOnChange

你必须确定,

var configuration = builder.Build()

在您的应用程序中只调用一次并将其存储在您可以访问它的地方(最好是避免它的静态字段)。

或者只禁用文件观察器。

  var builder = new ConfigurationBuilder()
        .AddJsonFile($"appsettings.json", true, false);

或清洁工:

var builder = new ConfigurationBuilder()
        .AddJsonFile($"appsettings.json", optional: true, reloadOnChange: false);

最好的方法是在接口后面抽象它并使用依赖注入。

public interface IConfigurationManager
{
    T GetAppConfig<T>(string key, T defaultValue = default(T));
}

public class ConfigurationManager : IConfigurationManager
{
    private readonly IConfigurationRoot config;

    public ConfigurationManager(IConfigurationRoot config)
        => this.config ?? throw new ArgumentNullException(nameof(config));

    public T GetAppConfig<T>(string key, T defaultValue = default(T))
    {
        T setting = (T)Convert.ChangeType(configuration[key], typeof(T));
        value = setting;
        if (setting == null)
            value = defaultValue;
    }
}

然后实例化并注册它

services.AddSingleton<IConfigurationManager>(new ConfigurationManager(this.Configuration));

并通过构造函数将其注入到您的服务中

错误 the configured user limit (128) on the number of inotify instances has been reached 发生的原因是正确的 - 在非 Windows 环境中 reloadOnChange 导致访问 appSetting.json 文件时出现问题。

但是有一个想法你在调整这个的时候可能会错过。我除了将 reloadOnChange 设置为 false 之外:

.AddJsonFile($"appsettings.json", optional: true, reloadOnChange: false);

您还应该确保您没有从默认 WebHost.CreateDefaultBuilder 开始,因为 inside it reloadOnChange 也设置为 true。因此,控制您的虚拟主机的最佳方式是从头开始配置它,而不需要不需要的选项(例如 WebHost.CreateDefaultBuilder 也执行 .UseIISIntegration(),这在您的环境中可能根本不需要)。

example of custom web host - Microsoft WebHost.CreateDefaultBuilder 的副本,但删除了 IISFileWatcher 依赖项,例如Linux 环境。