Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Instantiated services not disposed on exception during IStartable #1392

Open
Sputnik24 opened this issue Aug 29, 2023 · 1 comment
Open

Instantiated services not disposed on exception during IStartable #1392

Sputnik24 opened this issue Aug 29, 2023 · 1 comment

Comments

@Sputnik24
Copy link

From stackoverflow: https://stackoverflow.com/questions/76991305/autofac-dispose-of-created-services-not-called-when-exception-is-thrown-by-late

I have the following, minimal example to reproduce an issue of my real life application:

public class ServiceA : IStartable, IDisposable {
    public required ServiceB ServiceB { get; set; }
    
    public void Start() {
        ServiceB.Connect();
    }

    public void Dispose() {
        Console.WriteLine("ServiceA disposed");
    }
}

public class ServiceB : IDisposable {
    public void Connect() {
        throw new TimeoutException();
    }
    
    public void Dispose() {
        Console.WriteLine("ServiceB disposed");
    }
}

and a console application:

var builder = new ContainerBuilder();

builder.RegisterType(typeof(ServiceA)).AsSelf().As<IStartable>().SingleInstance();
builder.RegisterType(typeof(ServiceB)).AsSelf().InstancePerDependency();

var container = builder.Build();

Console.ReadKey();

container.Dispose();

Console.ReadKey();

From dependency chain ServiceB is a dependency of ServiceA and, therfore, is instanciated first on Build(). During Start() of ServiceA, Connect() on ServiceB is called which throws an Exception. The Exception is forwared to Build() which fails and the container is not created.

My expectation reading Autofac docs

Automatic Disposal To take advantage of automatic deterministic disposal, your component must implement IDisposable. You can then register your component as needed and at the end of each lifetime scope in which the component is resolved, the Dispose() method on the component will be called.

would be, that Dipose() on created ServiceB is called. This is not the case. ServiceB lives somewhere in my application and I cannot dispose it as IContainer was not created.

ChatGPT suggest to catch the exception and call Dispose() on IContainer later. This would mean, I need to check if Connect() on ServiceB was successfull (property bool IsConnected) and if not, I call Dispose().

Of course, this would solve my issue. But again, my expecation was, that Autofac is handling this for me via LifetimeScope.

@tillig
Copy link
Member

tillig commented Aug 29, 2023

Thanks for filing this - it's an interesting edge case. Container creation depends on the IStartable things running, but if those fail, disposal isn't executed. Hmmm.

I'm guessing we haven't handled this because, in general, if an application's container doesn't successfully build, the application itself is largely unusable. There's no "recovering," so the process terminates and the various finalizers are left to do their work to clean things up rather than actively calling Dispose().

Which isn't to say we shouldn't handle it, just that I can see why no one thought of that as a thing to test.

@tillig tillig changed the title Instanziated services not diposed on exception during IStartable Instantiated services not disposed on exception during IStartable Aug 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants