Out of memory exception occurs when enqueuing and processing background jobs - hangfire

I am able to cause a reproducible out of memory exception to occur when enqueuing and processing background jobs with Hangfire.
The jobs are simple Console.WriteLine invocations so I wouldn't expect heap memory to increase the way that it does.
Have I configured incorrectly or should I think about filing an issue?
Results (VMMap)
Using Redis as backing storage for Jobs:
At start, total heap = 29,088K;
after 5,000 jobs, 938,672K;
6,000 jobs, 1,056,004K;
7,000 jobs, 1,219,296K;
8,000 jobs, heap value is not present;
within 100 more jobs, the iisexpress.exe instance crashes.
With SQL storage the limit is much higher ~= 15,000 jobs.
Setup
empty ASP.NET project;
install Owin packages for IIS hosting and Hangfire;
startup class and controller.
Packages
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Hangfire.Core" version="1.6.6" targetFramework="net452" />
<package id="Hangfire.Pro" version="1.4.7" targetFramework="net452" />
<package id="Hangfire.Pro.PerformanceCounters" version="1.4.7" targetFramework="net452" />
<package id="Hangfire.Pro.Redis" version="2.0.2" targetFramework="net452" />
<package id="Hangfire.SqlServer" version="1.6.6" targetFramework="net452" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net452" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net452" />
<package id="Microsoft.AspNet.WebApi.Owin" version="5.2.3" targetFramework="net452" />
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.0" targetFramework="net452" />
<package id="Microsoft.Net.Compilers" version="1.0.0" targetFramework="net452" developmentDependency="true" />
<package id="Microsoft.Owin" version="3.0.1" targetFramework="net452" />
<package id="Microsoft.Owin.Host.SystemWeb" version="3.0.1" targetFramework="net452" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net452" />
<package id="Owin" version="1.0" targetFramework="net452" />
<package id="StackExchange.Redis" version="1.1.606" targetFramework="net452" />
</packages>
Controller
public class DefaultController : ApiController
{
static int _;
[HttpPost]
public void Post(int count = 1000)
{
for (var i = 0; i < count; ++i)
{
BackgroundJob.Enqueue(() => Console.WriteLine(_));
++_;
}
}
}
Startup
static class AppSettings
{
internal static bool HangfireUseRedis => true;
internal static int RedisDatabase => 0;
internal static string RedisConnection => "localhost:6379";
internal static string SqlConnection => "Data Source=(localdb)\\v11.0;Initial Catalog=Hangfire";
}
public class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
if (AppSettings.HangfireUseRedis)
{
var redisOptions = new RedisStorageOptions
{
Database = AppSettings.RedisDatabase,
Prefix = "Foobar:"
};
GlobalConfiguration.Configuration.UseRedisStorage(AppSettings.RedisConnection, redisOptions);
}
else
{
GlobalConfiguration.Configuration.UseSqlServerStorage(AppSettings.SqlConnection);
}
JobHelper.SetSerializerSettings(new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
app.UseHangfireServer();
app.UseHangfireDashboard();
app.UseWebApi(config);
}
}

After receiving your mini dump file (1.2 GB), I was able to get information about heaps of your process. Most of them don't contain anything interesting, and their size is relatively small, here is the excerpt for the most important onces:
GC Heap Size: Size: 0x9f7eb8 (10452664) bytes.
Jit code heap: Size: 0x1000 (4096) bytes total, 0x905a4d00 (2421837056) bytes wasted.
As we can see, GC Heap Size is about 10 MB, so there are no leaks in .NET code itself, since its size is relatively small. But Jit code heap looks very strange, so I decided to see what modules are used by the process, and found Stackify Profiler's one:
6b0d0000 6b23a000 StackifyProfiler_x86 (deferred)
PEB shows the environment variable StackifyIsPrefix=1 that tells us Stackify Prefix is used. Profilers may modify the JIT code for instrumentation puproses, so I've decided to install Stackify Prefix to try to reproduce the issue.
I've created a simple MVC application, modified the Home/Index action to enqueue 10000 of background jobs, and enabled the profiler. After doing this step, I've found that it takes too long to get that page – 1.5 minutes, and profiler didn't show any data. It was too long. So I decided to compare the timing with profiler turned off – it took only 5 seconds. That's a huge difference, but I was unable to reproduce memory problems.
I've decreased the number of jobs to 100, turned on the profiler and realized that every call to Redis is counted, there are hundreds of records for calls to Redis. Storing all of them may introduce memory issues, but I don't know exactly how they are stored in Stackify Prefix.
I was unable to reproduce the original memory issue. However, Stackify Prefix does significantly affect the execution by increasing its duration. Have you tried to disable the Stackify Prefix profiler and re-run your tests? Updated version may also fix the memory issue.

I can concur with the above comment from odinserj, because I wrote the Prefix profiler.
We've made some design changes to help account for background threads that run in libraries like Hangfire. The issue is that we keep shadow stacks in memory per thread - in a normal web app, we flush this stack when the request ends. But the threads that Hangfire spins up will exist for the lifetime of the app domain.
You'll find that in the lastest version, the impact should be much smaller, as we have accounted for some specific hangfire methods, and we then release some of that shadow stack.

Related

How can you prevent NLog from handling log statements in referenced libraries?

Whenever an error occurs within our API, we end up getting multiple emails for a single error. Based on the log messages; we can see that these other emails seem to be getting generated because various Microsoft libraries are calling something like _logger.LogError as well as our own _logger.LogError that happens when we handle the error.
For example, when there is a database timeout, we see 4 emails from these different classes:
Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware
Microsoft.EntityFrameworkCore.Database.Command
Microsoft.EntityFrameworkCore.Query
Web.Controllers.ErrorController (Our own exception handler; this is
the only one we want to see)
The last one is the only one that has our own error formatting with helpful information in it such as current user, etc. The others just contain a stack trace, which is already within our own formatted email.
We can't figure out for sure where these other log messages are coming from; but the most likely thing I can think of is that within Microsoft's libraries, they are calling _logger.LogError(), and our own NLog configuration is handling all instances of LogError; instead of just handling our own.
How can we prevent these other log statements from being logged and especially emailed to us?
This is our setup in Program.cs:
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
})
.UseNLog();
You could filter this in .NET Core - because your using the Microsoft.Extensions.Logging integration and Microsoft send the messages to that - and in NLog.
Configure in .NET Core
Modify you config, e.g. appsettings.json. For example at least an error for all Microsoft.* and Warning for Microsoft.EntityFrameworkCore.*
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Trace",
"Microsoft": "Error",
"Microsoft.EntityFrameworkCore": "Warning"
}
}
}
Note, this isn't NLog specific so you can't use the NLog level names. possible level names
Read more about this approach here.
Configure NLog
Or you could configure in the NLog config.
In the NLog.config, edit the <rules> .Those rules are processed from top to bottom.
You could filter the namespace with the name attribute (* are allowed)
Without a writeTo attribute, the logs are discarded
If a rule has final="true" and matching the events, the next rule won't be processed.
For example:
<rules>
<!--All logs, including from Microsoft-->
<logger name="*" minlevel="Trace" writeTo="allfile" />
<!--Skip non-critical Microsoft logs and so log only own logs-->
<logger name="Microsoft.*" maxlevel="Info" final="true" /> <!-- BlackHole without writeTo -->
<logger name="*" minlevel="Trace" writeTo="ownFile-web" />
</rules>
You could read about the nlog.config rules here.
This is also possible with the same approach from code, see here.

Serilog only logging the first time it is called after build

I have an ASP NET MVC project which uses Ninject for IoC. Have added a Serilog logger
public class LoggingModule : BaseModule
{
public override void Load()
{
var fileName = "c:\path\file.log";
var loggerConfiguration = new LoggerConfiguration()
.WriteTo.RollingFile(fileName, LogEventLevel.Debug)
.MinimumLevel.Verbose();
var logger = loggerConfiguration.CreateLogger();
Log.Logger = logger;
Bind<ILogger>().ToConstant(logger);
}
}
And am injecting this into a Controller.
When I exercise the code that uses it to log it will log once and then never again until I restart the web app.
I'm using the same configuration code (without ninject) in a windows service which works fine.
Versions installed are
<package id="Serilog" version="2.3.0" targetFramework="net45" />
<package id="Serilog.Sinks.File" version="3.1.0" targetFramework="net45" />
<package id="Serilog.Sinks.RollingFile" version="3.2.0" targetFramework="net45" />
<package id="Ninject" version="3.2.2.0" targetFramework="net45" />
<package id="Ninject.MVC3" version="3.2.1.0" targetFramework="net45" />
<package id="Ninject.Web.Common" version="3.2.3.0" targetFramework="net45" />
<package id="Ninject.Web.Common.WebHost" version="3.2.3.0" targetFramework="net45" />
<package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net45" />
Update:
Following on from Caio's answer. I added in the SelfLog and see...
2016-11-22T14:29:25.6317957Z Caught exception while emitting to sink Serilog.Core.Sinks.RestrictedSink: System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'The rolling log file has been disposed.'.
at Serilog.Sinks.RollingFile.RollingFileSink.Emit(LogEvent logEvent)
at Serilog.Core.Sinks.SafeAggregateSink.Emit(LogEvent logEvent)
Update 2:
This turned out to be a bug in the way that IDependencyResolver had been implemented in our project. IDependencyResolver implements IDisposable and our implementation called dispose on the kernel. (Un?)luckily this had just never caused an issue before.
I've marked Caio's answer as the answer because him pointing me to the SelfLog gave me the tool to unwind what was happening. Thanks to all the helped though!
Have you tried checking the output from Serilog's self log, to see if there's any error occurring internally?
e.g.
Serilog.Debugging.SelfLog.Enable(msg => Console.WriteLine(msg));
https://github.com/serilog/serilog/wiki/Debugging-and-Diagnostics
First question: Are you using one of the Ninject.MVC packages? If not, I'd try this first as they plug the Ninject container into the MVC pipeline correctly.
https://www.nuget.org/packages/Ninject.MVC5/
Also:
You can sometimes have an order-of-operations problem with DI containers. For this reason I find that it's unsafe to do much setup logic directly in the NinjectModule. I'd try something like this instead:
Bind<ILogger>().ToMethod(context => {
var fileName = "c:\path\file.log";
var loggerConfiguration = new LoggerConfiguration()
.WriteTo.RollingFile(fileName, LogEventLevel.Debug)
.MinimumLevel.Verbose();
var logger = loggerConfiguration.CreateLogger();
Log.Logger = logger;
}).In <whatever> Scope()

Access denied error when accessing usb stick files in Windows IoT core app

I want to access files (images, text files etc.) from an USB stick on my Raspberry Pi 2 using Windows 10 IoT Core.
So I've added the to the appxmanifest file.
When using this code in my IBackgroundTask I get an access denied error in the second line:
public sealed class StartupTask : IBackgroundTask
{
public async void Run(IBackgroundTaskInstance taskInstance)
{
//...
Windows.Storage.StorageFolder sf = Windows.Storage.KnownFolders.RemovableDevices;
//get list of drives
IReadOnlyList<Windows.Storage.StorageFolder> list = await sf.GetFoldersAsync();
...
}
}
I found that I should add the fileTypeAssociation with the file types I'd like to access in Package.appxmanifest so I did that:
<?xml version="1.0" encoding="utf-8"?>
<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:iot="http://schemas.microsoft.com/appx/manifest/iot/windows10" IgnorableNamespaces="uap mp iot">
<Identity Name="test-uwp" Publisher="CN=user" Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="8f31dff8-3a2b-4df1-90bb-2c5267f32980" PhonePublisherId="00000000-0000-0000-0000-000000000000" />
<Properties>
<DisplayName>test</DisplayName>
<PublisherDisplayName>user</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate" />
</Resources>
<Applications>
<Application Id="App">
<uap:VisualElements DisplayName="test" Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" Description="test" BackgroundColor="transparent" AppListEntry="none">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png">
</uap:DefaultTile>
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
<Extensions>
<Extension Category="windows.backgroundTasks" EntryPoint="test.StartupTask">
<BackgroundTasks>
<iot:Task Type="startup" />
</BackgroundTasks>
</Extension>
<uap:Extension Category="windows.fileTypeAssociation">
<uap:FileTypeAssociation Name="myimages">
<uap:SupportedFileTypes>
<uap:FileType ContentType="image/jpeg">.jpg</uap:FileType>
</uap:SupportedFileTypes>
</uap:FileTypeAssociation>
</uap:Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<uap:Capability Name="removableStorage" />
</Capabilities>
</Package>
If I want to deploy that, I get the following error:
Severity Code Description Project File Line Suppression State
Error Error : DEP0700 : Registration of the app failed.
AppxManifest.xml(37,10): error 0x80070490: Cannot register the
test-uwp_1.0.0.0_arm__yzekw4x8qxe1g package because the following
error was encountered while parsing the windows.fileTypeAssociation
Extension element: Element not found. . Try again and contact the
package publisher if the problem persists. (0x80073cf6)
As soon as I remove the uap:Extension element, the error goes away (but the access denied is still there).
Did I miss anything? Is it not possible to access files from an USB stick using a background service (I want to run that headless with no user interaction)?
At the moment you can't register a headless app that uses filetypeAssociation.
There is a workaround - see here: https://github.com/ms-iot/ntvsiot/issues/62
Simply add a headed app (project) to your solution (no need for any special code there).
Add a reference to this project in your headless app.
Now change the manifest of the headless (file asso..) and add Executable: YourHeadedApp.exe and EntryPoint: YourHeadedApp.App now with the next deploy the EXE will be included in deployment - so it can be found when the manifest is checked.

Optional Resources in Spring.Net

How to include Spring configuration files optionally? I think about something simular to this:
<spring>
<context>
<resource uri="file:///Objects/RequiredObjects.xml" />
<resource uri="file:///Objects/OptionalObjects.xml" required="false" />
</context>
This way I could provide developers the possibility to override some configuration parts (e.g. for a local speed improvement or automatism during app startup) without affecting the app.config and the problem that a developer could checkin his modified file when it is not really his intent to change the config for all.
Not as simple as in AutoFac (because there is already a builtin way) but possible to achieve something similar with a little coding:
using System.IO;
using System.Xml;
using Spring.Core.IO;
public class OptionalFileSystemResource : FileSystemResource
{
public OptionalFileSystemResource(string uri)
: base(uri)
{
}
public override Stream InputStream
{
get
{
if (System.IO.File.Exists(this.Uri.LocalPath))
{
return base.InputStream;
}
return CreateEmptyStream();
}
}
private static Stream CreateEmptyStream()
{
var xml = new XmlDocument();
xml.LoadXml("<objects />");
var stream = new MemoryStream();
xml.Save(stream);
stream.Position = 0;
return stream;
}
}
Register a section handler:
<sectionGroup name="spring">
...
<section name="resourceHandlers" type="Spring.Context.Support.ResourceHandlersSectionHandler, Spring.Core"/>
...
</sectionGroup>
...
<spring>
<resourceHandlers>
<handler protocol="optionalfile" type="MyCoolStuff.OptionalFileSystemResource, MyCoolStuff" />
</resourceHandlers>
...
<context>
<resource uri="file://Config/MyMandatoryFile.xml" />
<resource uri="optionalfile://Config/MyOptionalFile.xml" />
...
You'll find more information about resources and resource handlers in the Spring.Net documentation.

NLog fails to open file on Windows with Mono

I have a small set of ServiceStack REST services that is using NLog 2.1 (from NuGet) for logging.
My test server is running:
Windows 7
IIS 7.5
.NET 4.5
NLog config:
<nlog throwExceptions="true" internalLogToConsole="true" internalLogLevel="Debug" xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="c" xsi:type="Console" />
<target name="f1" xsi:type="File" fileName="C:\logs\test.log" />
</targets>
<rules>
<logger name="*" writeTo="c,f1" />
</rules>
</nlog>
My NLog config is exceedingly simple... just trying to get it working...
and in this configuration, everything works fine. NLog creates the log files correctly.
On my DEVELOPMENT machine, I am using:
Windows 7
Xamarin Studio / XSP4
Mono 3.2.3
Here is my Application_Start...
protected void Application_Start() {
LogManager.LogFactory = new NLogFactory();
ILog log = LogManager.GetLogger(typeof(Global));
log.Info("Application_Start called");
try {
new AppHost().Init();
} catch (Exception e) {
log.Error("Exception caught initializing AppHost");
}
}
In this configuration, my service's AppHost().Init() throws an exception as ServiceStack is registering my services in ServiceController.cs. I believe that part is irrelevant except that it is the first time something is logged outside of Application_Start (because both of the calls in Application_Start work... the log.info before the exception and the log.error after the exception).
Here is the exception that is shown:
The most relevant bit is that there was a System.NotImplementedException thrown at NLog.Internal.FileAppenders.BaseFileAppender.WindowsCreateFile (System.String fileName, Boolean allowConcurrentWrite).
I have found a workaround (in the accepted answer below). Hopefully anyone else who runs into this will quickly come upon this solution.
Some digging around on Google led me to this NLog pull request:
Avoid Win32-specific file functions in Mono where parts not implemented.
It appears that this change tries to use the preprocessor to NOT call WindowsCreateFile at all. However, for some reason, this still executes.
So I then went to check the newest version of BaseFileAppender.cs in the NLog GitHub repository to make sure someone didn't at some later point break this again.
#if !NET_CF && !SILVERLIGHT && !MONO
try
{
if (!this.CreateFileParameters.ForceManaged && PlatformDetector.IsDesktopWin32)
{
return this.WindowsCreateFile(this.FileName, allowConcurrentWrite);
}
}
catch (SecurityException)
{
InternalLogger.Debug("Could not use native Windows create file, falling back to managed filestream");
}
#endif
Hmmm... it's still there. What gives? Why doesn't MONO seem to be defined by the preprocessor, thus allowing this block to execute? I'm not sure. Before I started down that path of investigation, I noticed another change...
if (!this.CreateFileParameters.ForceManaged && ...
So after following that tracing that ForceManaged boolean back to it's origin, it appeared that I could set forceManaged="true" on my FileTarget declaration in my NLog config. Could it really be that simple?!
<nlog throwExceptions="true" internalLogToConsole="true" internalLogLevel="Debug" xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<targets>
<target name="c" xsi:type="Console" />
<target name="f1" xsi:type="File" forceManaged="true" fileName="C:\logs\test.log" />
</targets>
<rules>
<logger name="*" writeTo="c,f1" />
</rules>
</nlog>
Once that change was made, everything worked... the call to WindowsCreateFile that was throwing the exception was skipped & a managed filestream was used instead, which works great. Hallelujah!
Lastly, I could not find that forceManaged flag in the NLog documentation anywhere. Would likely have found this solution sooner if it was.