Rin
Rin copied to clipboard
Using Autofac and Rin causes problems on application shutdown
Hi! I love Rin! Unfortunately, it seems it doesn't like when used with Autfac.
I uploaded a repro repository here: https://github.com/kevindqc/RinShutdownProblemRepro
The problem happens when I run dotnet run
, and after that press CTRL+C.
The app doesn't close down properly. On the repro repository, it crashes, but in my actual project, it logs an error and the dotnet processes stay open - if I try to run dotnet run
it doesn't work because the files (DLLs) are in use. This slows down development considerably as I have to kill the 4 left-opened dotnet processes constantly.
The exception is:
Unhandled Exception: System.AggregateException: One or more errors occurred. (A task was canceled.) ---> System.Threading.Tasks.TaskCanceledException: A task was canceled.
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at Rin.Core.Event.MessageEventBus`1.Dispose()
at Autofac.Core.Disposer.Dispose(Boolean disposing)
at Autofac.Util.Disposable.Dispose()
at Autofac.Core.Lifetime.LifetimeScope.Dispose(Boolean disposing)
at Autofac.Util.Disposable.Dispose()
at Autofac.Core.Container.Dispose(Boolean disposing)
at Autofac.Util.Disposable.Dispose()
at Autofac.Extensions.DependencyInjection.AutofacServiceProvider.Dispose(Boolean disposing) in C:\projects\autofac-extensions-dependencyinjection\src\Autofac.Extensions.DependencyInjection\AutofacServiceProvider.cs:line 105
at Autofac.Extensions.DependencyInjection.AutofacServiceProvider.Dispose() in C:\projects\autofac-extensions-dependencyinjection\src\Autofac.Extensions.DependencyInjection\AutofacServiceProvider.cs:line 115
at Microsoft.AspNetCore.Hosting.Internal.WebHost.Dispose()
at Microsoft.AspNetCore.Hosting.WebHostExtensions.RunAsync(IWebHost host, CancellationToken token, String shutdownMessage)
at Microsoft.AspNetCore.Hosting.WebHostExtensions.RunAsync(IWebHost host, CancellationToken token)
at Microsoft.AspNetCore.Hosting.WebHostExtensions.Run(IWebHost host)
at RinShutdownProblemRepro.Program.Main(String[] args) in C:\Users\doyonke\source\repos\RinShutdownProblemRepro\RinShutdownProblemRepro\Program.cs:line 18
It seems that Autofac is disposing MessageEventBus
, which in its Dispose
method waits for a task, but that task has already been canceled. Maybe the dispose order is different when using Autofac vs. using MS Dependency Injection? I made a branch that doesn't use Autofac, and I don't seem to have the problem:
https://github.com/kevindqc/RinShutdownProblemRepro/tree/WithoutAutofac
When using default MS Dependency Injection, it will never call IDisposable.Dispose
method of services during shut down. However, Autofac calls that exactly, so that Task
throws an exception. I didn't recognize it.
I fixed it to ignore TaskCancelledException
during shut down, and published version 1.0.5.
@mayuki Awesome, thanks!
Are you sure it doesn't dispose? The documentation says it does in most situations.
If you add a service like this:
services.AddSingleton<Service2>();
The container will create the Service2
itself, and take care of disposing it. I tested it and it does dispose.
But if you create the object youself like this:
services.AddSingleton<Service3>(new Service3());
then it won't get disposed.
I see you are doing the later:
var eventBus = new MessageEventBus<RequestEventMessage>();
services.AddSingleton<IMessageEventBus<RequestEventMessage>>(eventBus);
Maybe it should be:
services.AddSingleton<IMessageEventBus<RequestEventMessage>, MessageEventBus<RequestEventMessage>>();
That way the dependency injected services will get disposed regardless of the container? But it might cause the problem I still have with Autofac, so it should probably get fixed first lol
I tried 1.0.5, and I don't see the exception being thrown, but I still see a dotnet
process outlast shutdown. I updated the repro to 1.0.5. If you run dotnet run
, press CTRL+C, a dotnet
process is still opened (at least on Windows). I've seen this problem in winforms app caused by a managed thread that is still doing stuff. Not sure about this case, there doesn't seem to be any thread manually created anywhere in the code :/
@kevindqc Thank you very much for your advice about DI behavior! I understand why injected instances aren't disposed of. sorry, It's my fault.
EventMessageBus
instances are independent which can be deleted in any order. Therefore, I will fix it with your suggestion.
Press Ctrl+C
to stop dotnet run
then the process seems like to exit correctly in the console.
However, I can see dotnet exec
process which is still running in the background. The process will terminate after waiting for a little.
I guess the HTTP server (Kestrel) is waiting for WebSocket connections to close. For example, Close the browser tab of Rin inspector
, wait 5 seconds and press Ctrl+C
, the process will terminate immediately.
Yeah I thought the same thing, websockets might keep the dotnet
process alive, but it happens even I don't have any browser window opened to /rin
or any MVC view that has the Rin In-View inspector (it's only a Web API)
Also, if the websockets are the cause of the dotnet
process to stay, wouldn't using MS DI have the same problem? Unless you had the DI container create the websockets (so they would get disposed with Autofac, which might cause waiting, but not MS DI). That doesn't seem to case though :(
For me using the repro project, when I CTRL+C it, the dotnet
stays for at a couple minutes at least (stopped waiting and I ended up just killing it). On my actual project, it causes 3 dotnet
processes to stay open, not sure why. At least, it seems like those processes are not locking down the DLLs anymore, so I can re-run dotnet run
without having to kill the dotnet
processes first.