Keep #RequestScoped context when receiving an async CDI event - asynchronous

I want to switch from firing CDI beans synchronous to asynchronous to be able to work stuff parallel.
event.fire(myObject) -> event.fireAsync(myObject)
As I currently use the request context to know what tenant the current process is about, I am confronted with the problem, that the #RequestScoped context is lost in a #ObservesAsync method. Therefor I don't know anymore to what db to persist etc. I could provide the necessary information in the cdi event object and recreate the requestcontext manually after recieving, but this would bloat my object and clutter my code.
Is there a way to simply keep the request context for a async cdi event?

Request scoped objects are not required to be thread-safe and usually are not. For that reason, request context is never automatically propagated across threads. For asynchronous events, indeed you should put all the necessary data into the event object.
You are of course not the first person to ask about this. There's been attempts to define an API/SPI for context propagation (MicroProfile Context Propagation, Jakarta Concurrency), including CDI request context, but they only work correctly in case of sequential processing with thread jumps (common in non-blocking/reactive programming). If you try to [ab]use context propagation for concurrent processing, you're signing up for troubles. For the latest discussion about this, see https://github.com/jakartaee/cdi/issues/474

I actually switched to using interfaces. This gives me more control and makes the code more understandable:
abstract class Publisher<T>{
#All
#Inject
private List<EventConsumer<T>> eventConsumers;
#Inject
private ContextInfo contextInfo;
#Inject
private MutableContextInfo mutableContextInfo;
...
public void publishEvent(T event){
String myContextInfo= contextInfo.getMyContextInfo();
eventConsumers.forEach(consumer -> notifyAsync(consumer, receivedObject, myContextInfo))
}
private void notifyAsync(EventConsumer<T> consumer, T object, String myContextInfo) {
Uni.createFrom()
.voidItem()
.subscribeAsCompletionStage()
.thenAccept(voidItem -> notifyConsumer(consumer, object, myContextInfo));
}
/**
* Method needs to be public to be able to activate request context on self invocation
*/
#ActivateRequestContext
public void notifyConsumer(EventConsumer<T> consumer, T object, String myContextInfo) {
mutableContextInfo.setMyContextInfo(myContextInfo);
try {
consumer.onEvent(object);
} catch (RuntimeException ex) {
log.error("Error while promoting object to eventconsumer", ex);
}
}
}

Related

How to keep a statefull bean clean or reset during a #QuarkusTest?

I test a statefull bean with a #QuarkusTest. It keeps a certain state. Obviously, I would like to have a fresh bean for every test. At the moment, each test might modify he current state, which is the effective for a oncoming test. This is highly undersireable and breaks my tests.
Is there a way to force a new bean clean bean getting injected for every test when running a #QuarkusTest?
Eg. A very basic subscription service, which holds the current subscription to avoid double subscriptions:
#ApplicationScoped
public class SubscriptionService {
#Inject
DeviceClient deviceClient;
private final Set<String> subscribedDevices = new HashSet<>();
public void subscribe(String deviceId, Consumer<RadarFrame> consumer){
if(subscriptions.contains(deviceId)){
return;
}
deviceClient.subscribe(deviceId, consumer);
subscriptions.add(deviceId);
}
public void unsubscribe(String deviceId, Consumer<RadarFrame> consumer){
deviceClient.unsubscribe(deviceId);
subscriptions.remove(deviceId);
}
}
I could manually unsubscribe the device after each test, which is a bad small as I use potention untested implemented logic for setup/teardown. It would be nice if a injected bean could be reinitialized before each test on a #QuarkusTest.
Or did I miss another clean option?
#ApplicationScoped beans will be there for the entire life of the container.
The recommended way to do this is to create a reset() method in the bean to later be called in tests. With JUnit 5 this would be something like:
#AfterEach
void tearDown() {
subscriptionService.reset();
}
You can make that method package friendly to limit it's usage.

.net transient database context being disposed prematurely

I am moving an asp.net mvc5 application using EF6 to asp.net core MVC 3.0 using EF Core.
In my mvc5 application I have some administrative operation that modify the database and take a long time, so I use a pattern when I create a new DBContext that is not the one that is associated with the request context and then run the task in the background using Task.Run. This has been working fine for years.
In converting to .net core it was unclear how to create a new DBContext in the way that I was doing it in my old codebase. It seems like I should be able to create a Transient DBContext in these cases and all should be fine.
So I created a subclass of MyDbContext called MyTransientDbContex and in my Configure class I added this service:
services.AddDbContext<MyTransientDbContex>(options =>
options.UseSqlServer(
context.Configuration.GetConnectionString("MyContextConnection")),
ServiceLifetime.Transient, ServiceLifetime.Transient);
In my controller I inject the context in the action that needs the transient service and spawn a thread to do something with it:
public ActionResult Update([FromServices] MyTransientContext context) {
Task.Run(() =>
{
try {
// Do some long running operation with context
}
Catch (Exception e) {
// Report Exception
}
finally {
context.Dispose();
}
}
return RedirectToAction("Status");
}
I would not expect my transient context to be disposed until the finally block. But I am getting this exception when attempting to access the context on the background thread:
Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'MyTransientContext'.'
And indeed the _disposed flag is set to true on the context object.
I put a breakpoint on the constructer for MyTransientContext and "Made an Object ID" of the this pointer so that I could track the object. This transient object is being created and is the same one that is inject into my controller action. It's also the same object that I'm trying to reference when the exception is thrown.
I tried setting a data breakpoint on the _disposed member in order to get a callstack on when disposed is being set to true, but the breakpoint won't bind.
I also tried overriding the Dispose method on MyTransientContext, and it isn't called until my explicit dispose in the finally block, which is after the exception is thrown and caught.
I feel like I'm missing something fundamental here. Isn't this what the transient services are for? What would dispose a Transient service?
One last detail - MyTransientContext is derived from MyContext, which is in turn derived from IdentityDbContext (Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContex)
Edit: The reason that I went down the path of using a Transient was because of this ef core document page: https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext. It states that "...any code that explicitly executes multiple threads in parallel should ensure that DbContext instances aren't ever accessed concurrently. Using dependency injection, this can be achieved by either registering the context as scoped and creating scopes (using IServiceScopeFactory) for each thread, or by registering the DbContext as transient (using the overload of AddDbContext which takes a ServiceLifetime parameter)."
As xabikos pointed out, this seems to be overriden by the scoping of the asp.net DI system, where it looks like anything created by that system is scoped to the request context, including Transient objects. Can someone point out where that's documented so that I can better understand how to work with the limitations?
f you want manage the lifetime of service, you can instantiate it manually (or use a factory) :
public ActionResult Update()
{
Task.Run(() =>
{
using(var context = new MyTransientContext(...))
{
try
{
// Do some long running operation with context
}
catch (Exception e)
{
// Report Exception
}
}
}
return RedirectToAction("Status");
}
Or you can use IServiceProvider to get and manage a service :
public class MyController
{
private IServiceProvider _services;
public MyController(IServiceProvider services)
{
_services = services;
}
public ActionResult Update()
{
var context = (MyTransientContext)_services.GetService(typeof(MyTransientContext));
Task.Run(() =>
{
using (context)
{
try
{
// Do some long running operation with context
}
catch (Exception e)
{
// Report Exception
}
}
}
return RedirectToAction("Status");
}
}
You mixed the concepts of transient objects that are created by internal DI container asp.net core provides.
You configure the MyTransientContext to be transient in the internal DI system. This practically means that every time a scope is created then a new instance is returned. For asp.net application this scope matches an HTTP request. When the requests ends then all the objects are disposed if applicable.
Now in your code, that is a synchronous action method you spawn a Task with Task.Run. This is an async operation and you don't await for this. Practically during execution this will be started but not wait to finish, the redirect will happen and the request will end. At this point if you try to use the injected instance you will get the exception.
If you would like to solve this you need change to an async action and await on the Task.Run. And most likely you don't need to spawn a new Task. But you need to understand that this is not probably the best way as it will need for the long operation to finish before the redirect takes place.
An alternative to this would be to use a messaging mechanism, and send a message that triggers this operation. And you have another component, like worker service that listens for those messages and process them.

Access session bean member variable from EJB asynchronous method

I have a #SessionScoped bean (CDI) that I would like to access and update from a EJB #Asynchronous method. If I pass a reference to a member variable in the bean via the #Asynchronous method's parameters and work with it, assuming the object being passed in is made thread safe, is there any other issues I should be aware of?
Is there any different to be aware if a #ViewScoped bean is used instead?
The only one I could think of would be if the CDI Session Bean timed out however that shouldn't be an issue because the object would be retained as the #Asynchronous method still has a reference to it.
I'm trying to pass off a long running task so as not to hold up the user clicking on a button but still update the session model with the result of the job so the user can see the outcome in a "job viewer" type interface.
Never access frontend classes from backend classes.
Just pass a callback to the EJB method.
#Asynchronous
public void asyncDoSomething(SomeInput input, Consumer<SomeResult> callback) {
SomeResult result = doSomethingWith(input);
callback.accept(result);
}
public void yourSessionScopedBeanMethod() {
yourEjb.asyncDoSomething(input, this::setResult);
}
public void setResult(SomeResult result) {
this.result = result;
}

HttpContextBase injection with Ninject 3 and SignalR 2.0

I have set up Ninject to work with SignalR (hosted on IIS) as described in the answer to this question: SignalR 2 Dependency Injection with Ninject.
This works in most cases, except when the client is disconnecting from the hub the HttpContext.Current variable is null and thus Ninject can't inject the value and throws an exception.
I've read up on the issue and found out that most people recommend that the current HttpContext should be retrieved from IRequest.GetHttpContext() (which is accessible from the hubs context). Sadly this doesn't help when trying to inject the value (I could pass on the context from the hub, but that would defeat the purpose of having dependency injection).
Code example (some parts removed for brevity):
public class TestHub : Hub
{
public TestHub(ITestService testService)
{
TestService = testService;
}
// When the disconnection request is issued, a ArgumentNullException
// for the HttpContext construction is thrown
public override Task OnDisconnected(bool stopCalled)
{
TestService.DoSomething();
}
}
public class TestService : ITestService
{
public TestService(HttpContextBase httpContext)
{
HttpContext = httpContext;
}
public void DoSomething()
{
// Service uses some data from the httpContext
TestLogger.Log(HttpContext.User.Identity.Name);
}
}
Is there any way to inject HttpContextBase into services that are in turn injected into SignalR hubs without accessing HttpContext.Current?
In case the HttpContext is actually available at construction time, you could use the following binding:
kernel.Bind<HttpContextBase>()
.ToMethod(ctx => Context.Request.GetHttpContext())
.WhenAnyAncestorMatches(ctx => typeof(Hub).IsAssignableFrom(ctx.Plan.Type));
The When condition checks whether the HttpContextBase is injected into a Hub (or derived class) or into any dependency of a Hub.
In case the HttpContextBase is only ever injected when contstructing Hubs, you could also just leave out the When condition.
I have worked around the issue now, and thus this is not a solution to the problem, but an unclean way to mitigate it.
Since the missing HttpContext only happens on client disconnects, I have first of marked all my injected services as Lazy<T>, so they don't get resolved immediately, but only when they are accessed. After applying this change, the exceptions are thrown only when code in the SignalR OnDisconnected event of the hub is triggered. So I had to modify the code in that is executed in the OnDisconnected method to use (or pass in as parameter) the context retrieved directly from the hub. In my case not much code gets executed in there, but it could become a problem if more is required in the future.
The patch applied to the sample code from my question:
public class TestHub : Hub
{
public TestHub(Lazy<ITestService> testService)
{
TestService = testService;
}
public override Task OnDisconnected(bool stopCalled)
{
DoSomethingThatInvolvesHttpContext(Context.Request.GetHttpContext());
}
}

Application_EndRequest triggered before request end?

I have some simple classes that need to be disposed a the end of the request.
For that end I call the Dispose method on those objects from the Application_EndRequest event in Global.asax.
This "works fine on my machine" but causes some problems on my production server where I get Cannot access a disposed object. This happens in some MVC helpers.
It seemed to me like Application_EndRequest is triggered at the end of the request. Is this not the case? Is there another event I should be using to dispose my objects?
Application pool issues - likely
I suspect that your disposable object isn't bound to request but rather app wide (it may be instantiated per request but it may be using some shared resources). As long as you're testing your application in development environment it seems to behave as expected but as soon as you put it in production you get issues. This indicates you may have problems with application pool.
IIS web application pool capabilities actually instantiate several HttpApplication instances for your application and they may all share common disposable resources. If that's the case with your disposable object and you're sharing it it may be that it isn't thread safe. The same would be true when you wouldn't wrap your shared resource usage inside thread safe operations.
That's why it may happen that while one request is in progress another one begins and the first one disposed the object while the second process still uses it.
More information is always helpful
If you'd explain the nature of your disposable object/resource and how you're using it in your application we could help you much better. But in the meantime, you could read my blog post that talks about application pools and handling them. It's not about disposable objects per se, but you may still find all the information very useful and helpful.
If you need some object disposable per-request to use inside your controllers, I would recommend you using controller's lifecycle handlers instead of using Application_BeginRequest and Application_EndRequest. See the following example.
The Controller:
public class BaseController : Controller
{
protected override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
this.HttpContext.Items["MyDisposableObject"] = new MyDisposableObject();
}
protected override void OnResultExecuted(ResultExecutedContext filterContext)
{
base.OnResultExecuted(filterContext);
if (this.HttpContext.Items.Contains("MyDisposableObject"))
{
var myDisposableObject =
this.HttpContext.Items["MyDisposableObject"] as IDisposable;
if (myDisposableObject != null)
{
myDisposableObject.Dispose();
}
}
}
}
The IDisposable object:
public sealed class MyDisposableObject : IDisposable
{
private bool disposed;
public void Dispose()
{
if (!this.disposed)
{
// Dispose all managed
// and unmanaged resources.
// Note disposing has been done.
this.disposed = true;
}
}
}
If the objects are scoped to controller level you can override the Dispose method of Controller to dispose those objects.
protected override void Dispose(bool disposing)
{
if(disposing)
{
// dispose the objects here
}
base.Dispose(disposing);
}
If you are using some DI framework (like Ninject) in your application you can delegate that job to them.
Instead of disposing the objects at the end of the request you can also try wrapping them in an using statement wherever you access by this way you make sure the object is disposed.

Resources