Open vegar opened 6 years ago
I am not familiar with Hangfire, but I would most certainly start with managing the scopes inside OnPerforming
and OnPerformed
and see where that takes you
It took me just a short step.
I'm having huge trouble with threads currently. Seems like async
/await
breaks the scope. Both for PerRequestLifetime()
-services on the webside, and PerScopeLifetime()
on the background worker.
I'm using MediatR
alot, and have opened an issue there to see if Bogard is able to explain what's going on.
Anyway, 'mid-request', Lightinject throws exception telling me there is no request scope available, and on the background worker, I get new instances for services where I expected to receive same instance as long as I haven't ended the scope.
😢
From my IoC config:
var container = new ServiceContainer {
ScopeManagerProvider = new PerLogicalCallContextScopeManagerProvider()
};
container.Register<IPrincipalProvider, HangfireJobPrincipalProvider>(new PerScopeLifetime());
The IPrincipalProvider
has methods for setting and getting current user.
In my IServerFilter
, I have code like this: (passing the container to the constructor of the filter...)
public void OnPerforming(PerformingContext filterContext)
{
var scope = _container.BeginScope();
filterContext.Items[key] = scope;
var user = filterContext.GetJobParameter<Identity>("User");
if (user != null) {
var p = _container.GetInstance<IPrincipalProvider>()
p.SetUser(user);
}
}
public void OnPerformed(PerformedContext filterContext)
{
var scope = filterContext.Items[key] as Scope;
scope.Dispose();
}
And it doesn't work....
When instances of my IParticipantProvider
-interfaces are injected into code, it receives new copies instead of the previously populated instance.
One thought that just came to me: Could my problem be related to services with different lifetime depending on each other? Except - all other services are basically transient, so I can't see the problem there either....
A small repro of this would be very useful. How is this hosted? Is it a web app and if so, is it an IIS web app? I'd love to get to the bottom of this, but I really need something to look at where I can set a breakpoint and see it fail. There are so many ifs and buts when it comes to ambient context depending on the hosting environment. Also take a look at #386 for more information about HttpContext.Current and async/await.
I would love to create a small repo, but I'm not sure I'll manage...
Anyway. It's a Azure Cloud Service hosted project with one WebRole and one WorkerRole. Both are targeting .NET Framework 4.5.2 and hosted in IIS Express when running locally.
I had a look at #386 earlier, and have to admit that it goes a little over my head... Same for the 4.7.1 feature that was announced. As I understand it, it gives an option to manually restore context between execution steps?
None of this should relate to the problems I have with the background worker, though, should it?
When it says No .ConfigAwaiter(false)
- I can of cause prevent such a call in my code, but if I await a library method, and that method awaits another call, with .ConfigAwaiter(false)
- does that count? Will that break the chain?
Will that break the chain?
It could, but that scenario should be rare. If you inject some Func<T>
somewhere that is used to resolve a scoped instance, it could break if you're somehow lost the synchronization context. I would not worry to much about that, but it is something to be aware of.
If I understand correctly, your main issue here is to ensure a single IPrincipalProvider
across the boundaries of OnPerforming
and OnPerformed
?
https://www.hangfire.io/extensions.html#ioc-containers
You are aware of this I assume?
Yes, my goal is to ensure a single instance of IPrincipalProvider
across the bounderies of OnPerforming
and OnPerformed
.
We are using @sbosells extension to inject dependencies into our job implementations. When looking at the source, I see there is some scope handling there as well. I'm not sure how that applies, though.
These projects simplify the integration between Hangfire and your favorite IoC Container. They provide custom implementation of JobActivator class as well as registration extensions that allow you to use unit of work pattern or deterministic disposal in your background jobs. https://www.hangfire.io/extensions.html
Maybe I already have 'per job'-lifetime handling out of the box?
Yeah, I would at least try to use the extension first. It has a few thousands downloads on NuGet too 👍
Did you get any further with this?
Not yet. Been occupied with other things :-)
From: Bernhard Richter notifications@github.com Sent: Wednesday, May 16, 2018 5:32:11 PM To: seesharper/LightInject Cc: Vegar Vikan; Author Subject: Re: [seesharper/LightInject] Implementing PerJobLifetime() for use with Hangfire (#416)
Did you get any further with this?
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHubhttps://github.com/seesharper/LightInject/issues/416#issuecomment-389562655, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AAuqZYVIspVFTmJtpHbmXuHPqoW4VvAFks5tzEZ6gaJpZM4T7oSo.
I'm trying to understand scope management in LightInject by looking at the scope manger from the LightInject.Web project. The goal is to ensure that each job inside of
Hangfire
gets their own instance of services.As far as I have found, there is no global state available in hangfire - meaning that there is no
Hangfire.CurrentJob
or anything similar to theHttpContext.Current
for web applications. What do exist, though, is aIServerFilter
withOnPerforming
andOnPerformed
methods, both being passed aPerformContext
-object with a dictionary where key-value pairs can be added.Should I just use the
PerScopeLifetime
-class and begin new scopes inOnPerforming
and end them inOnPerformed
? Or would it make more sense to implement aPerJobLifetime
similar to thePerRequestLifeTime
with its own scope manager and everything?