Essay - Published: 2024.09.20 | asp-dotnet | create | csharp | dotnet | fsharp | linux | tech | unix |
DISCLOSURE: If you buy through affiliate links, I may earn a small commission. (disclosures)
I recently ran into a problem with one of my dotnet projects - TravelMap. It started throwing an exception System.IO.IOException: The configured user limit (8192) on the number of inotify instances has been reached which crashed my app and blocked it from spinning up its webserver.
Here I'll share how I resolved it so hopefully it can unblock you as well.
First a bit of context on the app itself and how it's hosted so you can understand the environment it was running in and get a better idea if this exception / fix is relevant to your app setup or not.
Host.CreateDefaultBuilder()For more information on TravelMap and how it's built, checkout the TravelMap project page
The System IOException was thrown when my container tried to startup. On debugging it appeared that the container failed in configuration during startup.
The full exception message:
Unhandled exception. System.IO.IOException: The configured user limit (8192) on the number of inotify instances has been reached, or the per-process limit on the number of open file descriptors has been reached.
According to Stack Overflow this can often happen when running dotnet on Linux / Unix and is often caused by too many file watchers on a configuration file. This matched up with what I was doing and my exception's logs so is likely what caused this issue.
One of the recommended ways to fix this exception is to set reloadOnChange=false in the ConfigurationBuilder for your file. This will prevent the builder from opening up additional file watchers and thus will not run into this issue.
I did this and it fixed my problem so seems to work.
My ConfigurationBuilder after the fix:
let fetchConfiguration (environment_name : string) =
let targetConfigurationFile = (
if environment_name.ToLower() = "development"
then "appsettings.Development.json"
else "appsettings.json")
let configurationRoot = (
(ConfigurationBuilder())
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile(targetConfigurationFile, false, reloadOnChange=false)
.Build())
let root = configurationRoot.Get<AppConfiguration>()
root
Note: This fix works by preventing new filewatchers on configuration files - this means dotnet will not reload if this file changes. This is fine for my case because I know my configuration will never change during the lifecycle of my app - if there is a change, I would deploy a new container. For some cases this may not work (like local hotreloading) so use with discretion.
This unblocked me and was pretty simple so I decided to log this for posterity in the hope that it helps others and saves me time when I inevitably run into this again. I've gone ahead and added this fix into CloudSeed (my F# project boilerplate for webapps) so that I can avoid this when spinning up new apps.
Want to get started building webapps with F#? Spin up a fullstack F# web app in 10 minutes with CloudSeed
If you liked this post you might also like:
The best way to support my work is to like / comment / share for the algorithm and subscribe for future updates.