I am using the Spring WebClient (org.springframework.web.reactive.function.client.WebClient) in order to implement some non-blocking behaviour.
Mono<ClientResponse> clientResponse =
webClient
.get(...).exchange();
clientResponse.subscribe((response) -> {
//--- unfortunately my tenant context is lost here !!! Someone knows the right solution?
});
However my tenant-context gets lost once the response arrives (of course, we are in a new thread).
Here is the documentation of how to implement common asynchronous tasks within the tenant-context: https://sap.github.io/cloud-sdk/docs/java/features/multi-tenancy/multi-tenancy-thread-context/
However, I couldn't find the recommended way how to remain the tenant-context using Spring webflux (using the WebClient).
Edit: The SAP Cloud SDK destroys a ThreadContext at the end of an operation. This is done to prevent it from leaking e.g. when the thread is re-used.
If:
the context is passed to an asynchronous operation
but the "parent" operation is done before the asynchronous operation starts
the ThreadContext will not be available in the asynchronous operation. That is what is happening when using the WebClient.
This is not true for custom properties, the SDK does not clear them. But that also means that you have to clear them yourself to ensure they don't leak when the thread is being re-used.
I'd recommend not to use the multi tenancy features of the SDK in such cases. Still, I'll leave my below answer in for context.
You can transfer the SAP Cloud SDK's ThreadContext to any new Thread if and only if you have control:
Before the new Thread is created
The operation that will be run asynchronously that requires the context
Edit: The parent thread (context) still exists
I am not too familiar with WebFlux, but I'll assume that:
clientResponse.subscribe runs in the parent Thread
And the lambda is executed in the asynchronous Thread
Given that, the following should transfer the ThreadContext to be present in the lambda:
ThreadContextExecutor executor = new ThreadContextExecutor();
clientResponse.subscribe((response) ->
executor.execute(() ->
{
// your code goes here, the ThreadContext should be available
}
)
);
You would have to do this at every point where an operation is running in a new Thread. As Artem pointed out, currently there is no feature in the SDK for this that would achieve the same automagically.
I think it is also possible to define a custom ExecutorService that Spring will use to create and run new Threads. In a custom executor you could encapsulate this wrapping logic once for all operations.
The SAP Cloud SDK APIs support Spring Boot and currently don't support Spring Webflux out of the box. You'll probably see all sorts of errors if using the SDK APIs with reactive Spring development. On the other hand, as Matthias showed workarounds might be possible for certain use-cases.
We consider adding Spring WebFlux support in the future. It probably won't happen this year (in 2021).
Related
I currently am using Spring Integration to get messages off of a queue and send them to a service using a service activator. My issue is that the service I am calling requires a security context to be in place for the current thread. This can be setup by calling a no-argument method, handleAuthentication(), of another bean. I am wondering what the best way is to call this whenever a new message is received, prior to calling the service activator service? I was originally thinking I would chain together two service activators, with the first one calling handleAuthentication(), but this seems incorrect as handleAuthentication() does not require any information from the actual message.
Yes, your assumption about the security handling is correct. It is really just a side-effect aspect which should not be tied with the business logic.
Therefore we should use something which allows us to follow with the same behavior in the program. It is called as an Aspect in the programming as well.
For this purpose Spring Integration suggests a hook like MessageChannelInterceptor, where you can implement your handleAuthentication() exactly in the preReceive() callback, according to your explanation.
Another trick can be achieved with the <request-handler-advice-chain> and MethodInterceptor implementation which should populate the SecurityContext into the current thread just before target service invocation.
we are facing an issue with initializing our cache at server startup or application deployment. Initializing the cache involves
Querying a database to get the list of items
Making an rmi call for each item
Listening to the data on a JMS queue/topic
Constructing the cache
This initialization process is in startup code. All this is taking lot of time due to which the deployment is taking lot of time or server start time is increasing.
So what I proposed is to create a thread in the startup and run the initialization code in it. I wrote a sample application to demonstrate it.
It involves a ServletContextListener, a filter. In the listener I am creating a new thread in which the HeavyProcess will run. When it finishes an event will be fired which the filter will be listening. On receiving the event the filter will allow incoming http requests. Until then the filter redirects all clients to a default page which shows a message that the application is initializing.
I presented this approach and few concerns were raised.
We should not ideally create a thread because handling the thread will be difficult.
My question is why cant we create a thread like these in web applications.
If this is not good, then what is the best approach?
If you can use managed threads, avoid unmanaged ones. The container has no control over unmanaged threads, and unmanaged threads survive redeployments, if you do not terminate these properly. So you have to register unmanaged threads, and terminate these somehow (which is not easy as well, because you have to handle race-conditions carefully).
So one solution is to use #Startup, and something like this:
#Schedule(second = "*/45", minute = "*", hour = "*")
protected void asyncInit(final Timer timer) {
timer.cancel();
// Do init here
// Set flag that init has been completed
}
I have learned about this method here: Executing task after deployment of Java EE application
So this gives you an async managed thread, and deployment will not be delayed by #PostConstruct. Note the timer.cancel().
Looking at your actual problem: I suggest using a cache which supports "warm starts".
For example, Infinispan supports cache stores so that the cache content survives restarts. If you have a cluster, there are distributed or replicated caching modes as well.
JBoss 7 embeds Infinispan (it's an integrated service in the same JVM), but it can be operated independently as well.
Another candidate is Redis (and any other key/value store with persistence will do as well).
In general, creating unmanaged threads in a Java EE environment is a bad idea. You will loose container managed transactions, user context and many more Java EE concepts within your unmanaged thread. Additionally unmanaged threads may block the conainer on shutdown if your thread handling isn't appropriate.
Which Java EE Version are you using? Perhaps you can use Servlet 3.0's async feature?
Or call a asynchronous EJB for doing the heavy stuff at startup (#PostConstruct). The call will then set a flag when its job is done.
I have a WCF web service hosted in IIS- This service has a method - lets call it DoSomething(). DoSomething() is called from a client-side application.
DoSomething performs some work and returns the answer to the user. Now I need to log how often DoSomething is being called. I can add it to the DoSomething function so that it will for every call write to an sql database and update a counter, but this will slow down the DoSomething method as the user needs to wait for this extra database call.
Is it a good option to let the DoSomething method spawn a new thread which will update the counter in the database, and then just return the answer from the DoSomething method to the user without waiting for the thread to finnish? Then I will not know if the database update fails, but that is not critical.
Any problems with spawning a new background thread and not wait for it to finnish in WCF? Or is there a better way to solve this?
Update: To ask the question in a little different way. Is it a bad idea to spawn new threads insde a wcf web service method?
The main issue is one of reliability. Is this a call you care about? If the IIS process crashes after you returned the response, but before your thread completes, does it matter? If no, then you can use client side C# tools. If it does matter, then you must use a reliable queuing technology.
If you use the client side then spawning a new thread just to block on a DB call is never the correct answer. What you want is to make the call async, and for that you use SqlCommand.BeginExecute after you ensure that AsyncronousProcessing is enabled on the connection.
If you need reliable processing then you can use a pattern like Asynchronous procedure execution which relies on persisted queues.
As a side note things like logging, or hit counts, and the like are a huge performance bottleneck if done in the naive approach of writing to the database on every single HTTP request. You must batch and flush.
If you want to only track a single method like DoSomething() in service then you can create an custom operation behavior and apply it over the method.
The operation behavior will contain the code that logs the info to database. In that operation behavior you can use the .NET 4.0's new TPL library to create a task that will take care of database logging. If you use TPL you don't need to worry about directly creating threads.
The advantage of using operation behvaior tomorrow you need to track another method then at that time instead of duplicating the code there you are just going to mark the method with the custom operation behavior. If you want to track all the methods then you should go for service behavior.
To know more about operation behaviors check http://msdn.microsoft.com/en-us/library/system.servicemodel.operationbehaviorattribute.aspx
To know more about TPL(Task Parallel Library) check http://msdn.microsoft.com/en-us/library/dd460717.aspx
I've seen a project lately using a background worker to make some operations (get data from other web services) and throw the data using events to the client. This project is a WCF service and consume by an ASP.NET web site by another class library as WCF client role and throwing in turn events to the application. This all multithreaded series made me curious to examine. I've seen that this is a basicHttpBinding binding and the only behavior to the service is the UseSynchronizationContext=false where I found out that they added it after unexplained exception which is normal :)
Now I'm asking about the default ConcurrencyMode for the basicHttpBinding. Shouldn't they make it Reentrant or this is the default behavior?
Is this scenario will continue failing cause they already have an unexplained reference not set to an instance of an object if the WCF service is down from the client?
I believe using multithread operations in a WCF service consume by ASP.NET project which relies on IIS handling is bad cause the page could be sent to the client before the WCF service return data to the client class library and append these to the page.
Can you discuss the above and explain your thoughts?
Shouldn't be better when you need such an asynchronous programming style to inform WCF comsumers to notify after long operation using CallbackContracts and embedded WCF technologies, rather multithreading operations?
Need clarification to correct the design and have some proves that this is a bad service architecture, if it is for real, which I suspect!
Thank you.
It is not inherently bad architecture, but it sounds like it does create a number of possible pitfalls.
The WCF client library is leaving all the coordination up to the ASP.NET application. If the ASP.NET app isn't checking that a call to the WCF service has been completed, then it risks using variables before they have been set with values from the service, and other such race conditions unless explicitly setting up some manner of coordinating the initial call against the completion events.
My recommendation would be to rewrite the WCF client asynchronous methods to return Task objects, from the System.Threading.Tasks namespace (MSDN reference). In this way you can spin off the background processing calling the WCF service, and use the Result property of the Task to ensure the service has completed.
An example:
protected void Page_Load(object sender, EventArgs e)
{
Task<string> t = Task<string>.Factory.StartNew(() =>
{
return MyWcfClientClass.StaticAsyncMethod(MyArguments);
}
/* other control initialization stuff here, while the task
and WCF call continue processing in background */
/* Calling Result causes the thread to wait for the task to
complete as necessary, to ensure we have our correct value */
MyLabel1.Text = t.Result;
}
We have created a WCF RESTful service for a WPF(UI) Application. The UI sends a request to the WCF Service which then invokes a suitable method in BLL, which in turn invokes a method in DAL. All these layers have been separated using IOC/DI.
Now, for a new feature, we want that when a new object of a certain type is added to the database, it should go through 3 steps which would be performed in a separate thread.
That is, if service sends a request to BLL to add a new object OBJ to the database, the BLL should save the object into database through the DAL and then initiate a new thread to perform a some actions upon the object without blocking the WCF Request.
But whenever we try to do so by starting a new thread in the BLL, the application crashes. It is so because the 'InRequestScope' object of the database context has been disposed and the thread cannot update the database. Also the WCF request does not ends until the thread is completed, although the return value has been provided and the BLL method has completed execution.
Any help would be much valued.
I have figured out the solution and explanation for this behavior. Turns out to be a rather silly one.
Since I was creating a thread from the BLL (with IsBackground = true;), the parent thread (originated by the service request) was waiting for this thread to end. And when both the threads ended, the response was sent back to the client. And the solution, well, use a BackgroundWorker instead, no rocket science, just common sense.
And for the disposing of context, since the objects were InRequestScope, and the request had ended. So every time a Repository required a UnitOfWork (uow/context), it would generate a new context and end it as soon as the database request was complete. And the solution would be, create a uow instance, store in a variable, pass it to the repository required to be used, and force all repositories to use the same uow instance than creating a new one for itself.
This seem more of a client-side concern than a service-side concern. Why not have the client make asynchronous requests to WCF service since this automatically provides multi-threaded access to the service.
The built-in System.Net.WebClient (since you're access a webHttpBinding or WCF Web API endpoint) can be used asynchronously. This blog post gives a quick overview of how it is done. Although this MSDN article seems to apply to file I/O, about three quarters down, there is a detailed explanation on coding asynchronous WebClient usage.