I am working on an application, where we have to establish, that some steps of the now synchronously working program become asynchron. We are using JSF for frontend and we have managedbeans and EJB-s.
After looking a little bit deeper into the topic, I found, that we can not make asynchronous methods in ManagedBeans, because they are not supported, so they will not work in most situations(in theory for nobody, but it worked for some people according to comments).
In theory I know that supporting an asynchronous execution means, that the asynchron funtion exection will happen with a new thread. After I started the asynchronous execution I can call other functions (like println), in the function. So does this mean, that I can call back into the managed beans as well? Or do they not support that part of the asynchronous execution? And if not, why is it not possible?
By call back I meant something like this:
#ManagedBean
#ViewScoped
public class managedBean{
#EJB
private AsynchronClass asychronClass;
public void function(){
asychronClass.callAsynchronFunction(this);
}
public void functionAsynch(){
//do the original things
}
}
#LocalBean
#Stateless
public class AsychronClass{
public void callAsynchronFunction(managedBean mB){
mB.functionAsynch();
}
}
Related
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.
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);
}
}
}
New to WebFlux, reactive, and handlers.
I am able to get a Mono<> from a ServerRequest and process the contained POJO to add a new tuple to a database. But, it seems like there should be a "better" or "more accepted" way to write this code.
Any help/input with the code in AccountRequestHandler would be appreciated, especially with explanations of the rationale behind the recommend change(s).
Router implementation (stripped down to only "POST")...
#Configuration
public class AccountRequestRouter {
#Bean
public RouterFunction<ServerResponse> route(AccountRequestHandler requestHandler) {
return nest(path("/v2"),
nest(accept(APPLICATION_JSON),
.andRoute(RequestPredicates.POST("/accounts"), requestHandler::addAccount)
));
}
}
Handler implementation...
The code where I'm actually doing the add, and then separately creating a ServerResponse, is what I'm focused on. It seems "clunky", especially since AccountService.addAccount() returns a Mono on completion.
#Component
public class AccountRequestHandler {
#Autowired
private mil.navy.ccop.service.accounts.account.AccountService accountService;
public Mono<ServerResponse> addAccount(ServerRequest request) {
return request.bodyToMono(Account.class).flatMap(account -> {
accountService.addAccount(account);
return ServerResponse.ok().build();
})
.switchIfEmpty(ServerResponse.badRequest()
.contentType(APPLICATION_JSON)
.build(Mono.empty()));
}
}
AccountService implementation (again, stripped down)...
#Service
class AccountService {
#Autowired
private AccountRepository accounts;
public AccountService() {
}
public Mono<Void> addAccount(Account account) {
Account proxy;
// make sure that accountId is set to support auto-generation of synthetic key value
proxy = new Account(-1, account.getShortName(), account.getLongName(), account.getDescription());
accounts.save(proxy);
return Mono.empty();
}
}
Appreciating all the help in ramping up on this style of programming....
well first of all, you have 2 addAccount, that can be a bit confusing.
Second of all, what kind of "repository" are you writing too? if its an sql repo you need to properly wrap it in a Mono.fromCallable() otherwise it will block the Reactive thread pool and you can have really bad performance.
Yes there are other ways of doing things. A lot of people tend to do things in flatmap or map and sure it is completely possible to do things here, but for the semantics i'd say it is less good.
map and flatmap are usually used to perform some sort of computation on the inner value of the mono and then return the same or a new value and or type inside the mono.
i would rewrite this like such.
return void here:
public void addAccount(Account account) {
Account proxy;
// make sure that accountId is set to support auto-generation of synthetic key value
proxy = new Account(-1, account.getShortName(), account.getLongName(), account.getDescription());
accounts.save(proxy);
}
And here:
public Mono<ServerResponse> addAccount(ServerRequest request) {
return request.bodyToMono(Account.class)
.doOnSuccess(account -> {
accountService.addAccount(account);
}).then(ServerResponse.ok().build())
.switchIfEmpty(ServerResponse.badRequest()
.contentType(APPLICATION_JSON)
.build());
}
there are a number of different doOn methods that are ment to be used to consume and do "side effects" on things. Like doOnSuccess, doOnError, doOnCancel etc. etc.
you also have then and thenReturn which will just return whatever you put in them. Then returns whatever Mono you put in it. thenReturn wraps whatever value you put into it into a Mono and returns it.
Is instance of Feign thread safe...? I couldn't find any documentation that supports this. Do anyone out there think otherwise?
Here is the standard example posted on github repo for Feign...
interface GitHub {
#RequestLine("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(#Param("owner") String owner, #Param("repo") String repo);
}
static class Contributor {
String login;
int contributions;
}
public static void main(String... args) {
GitHub github = Feign.builder()
.decoder(new GsonDecoder())
.target(GitHub.class, "https://api.github.com");
// Fetch and print a list of the contributors to this library.
List<Contributor> contributors = github.contributors("netflix", "feign");
for (Contributor contributor : contributors) {
System.out.println(contributor.login + " (" + contributor.contributions + ")");
}
}
Should I change this to following... Is it thread safe...?
interface GitHub {
#RequestLine("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(#Param("owner") String owner, #Param("repo") String repo);
}
static class Contributor {
String login;
int contributions;
}
#Component
public class GithubService {
GitHub github = null;
#PostConstruct
public void postConstruct() {
github = Feign.builder()
.decoder(new GsonDecoder())
.target(GitHub.class, "https://api.github.com");
}
public void callMeForEveryRequest() {
github.contributors... // Is this thread-safe...?
}
}
For the example above... I've used spring based components to highlight a singleton. Thanks in advance...
This discussion seems to suggest that it is thread safe. (Talks about creating a new object being inefficient)
Had a look at the source and there doesn't seem to be any state that would make it unsafe. This is expected as it is modelled on the jersey Target. But you should get a confirmation from the Feign devs or do your own tests and review before using it in an unsafe way.
I was also looking, but unfortunately found nothing. The only signs provides in Spring configuration. The builder is defined as bean in scope prototype, so should not be thread safe.
#Configuration
public class FooConfiguration {
#Bean
#Scope("prototype")
public Feign.Builder feignBuilder() {
return Feign.builder();
}
}
reference: http://projects.spring.io/spring-cloud/spring-cloud.html#spring-cloud-feign-hystrix
After a deep dive into the feign-core code and a couple other feign modules (we needed additional support for things that weren't there so I had to modify some stuff -- plus, this question made me curious so I took another look), it looks like you should be safe re-using Feign clients in a multi-threaded environment as long as all of your local code (such as any custom Encoder, Expander, or RequestInterceptor classes, etc) has no mutable state.
The Feign internals don't store much in the way of mutable state, but some things are cached and re-used (thus may be called from multiple threads at the same time, if you are calling your Feign target's methods from multiple threads at the same time), so your plugins should be stateless.
It looks to me like all the main Feign modules were written with immutability and statelessness in mind as a goal.
In feign/core/src/main/java/feign/Client.java, there is a comment
/**
* Submits HTTP {#link Request requests}. Implementations are expected to be thread-safe.
*/
public interface Client {
So, from the designer's point of view, it should be thread-safety.
I've looked at 'Messenger and references' discussion, but I'm writing a new topic, because my issue is not technical, and I don't want to offtop there.
I've encountered a doubt - Have I to code cleanup()/RequestCleanup() method implementation to unregister previously registered Messenger in my viewmodel class? I'm afraid of memory leaks in the future.
I think I've found the documentation not to be enough bright for me.
Description of Messenger.Register is: '... Registering a recipient does not create a hard reference to it, so if this recipient is deleted, no memory leak is caused.'
1) Is this mean that I don't have to take care of it and implement-develop following solutions?
On the other hand, we can find in the code of GalaSoft.MvvmLight.ViewModelBase abstract class the short info about the Cleanup() method:
//
// Summary:
// Unregisters this instance from the Messenger class.
// To cleanup additional resources, override this method, clean up and then
// call base.Cleanup().
public virtual void Cleanup();
so 2) Is only invoking a Cleanup enough to unregister class-instance out of the Messenger?
3) Or maybe I have to invoke Messenger.Default.Unregister(this); in the body of a Cleanup method?
4) In the Unregister(Object) doc we read 'Unregisters a messager recipient completely' - what does the 'completely' mean?
I'm very sorry if my post seems to have out of the context quotes, I wanted to point out what I'm more interested in.
EDIT 1:
Hello Joel, thanks for reply. I've got several questions:
1) I have used your code. There's defined override void Cleanup() in CustomerMasterViewModel. Where to call it? Should I declare destructor in this case or maybe the ViewModelBase has an automatic mechanism for invoking the Cleanup()?
2) I have in my project another base class from a different toolkit, so my VMs cannot derive from both at the same time. How to organise your code to get the same effect by implementing only ICleanup interface?
public class CustomerMasterViewModel : SomeBaseClass, ICleanup
{
public CustomerMasterViewModel()
{
Messenger.Default.Register<Message>(this, this.MessageReceived);
}
#region messages
private void MessageReceived(Message obj)
{
//do something
}
#endregion
#region helper methods
public override void Cleanup()
{
//base.Cleanup();//there's no implementaction in an interface
ViewModelLocator.Cleanup();
}
#endregion
}
You have to invoke the Cleanup() method in GalaSoft.MvvmLight.ViewModelBase on each of you view models you wan't to dispose don't need any longer.
Example:
Let say your application has a tab control with different tabs. Each of your tabs displays a UserControl which has a dedicated ViewModel. The user has the ability to close a tabs which causes the underlining ViewModel to become obsolete.
Want you want to do now is to clean up the ViewModel calling the Cleanup() method in GalaSoft.MvvmLight.ViewModelBase. This will unregister ALL registered messages. The GarbageCollector will take care of you viewmodel if there are no other references.
Assuming you use the ViewModelLocator which also comes with the MVVM Light Framework you're not done yet because at least the ViewModelLocator itself has a reference to your viewmodel! Therefore the Garbage Collector can't finalize your viewmodel.
But it also has another side effect. When the user reopens the tab (Lets say the user is able to do so) the UserControl is loaded again and the ViewModelLocator will give you the same ViewModel instance. The only difference is that there are not registered messages because you cleaned them by calling the CleanUp() method.
What you need is a new instance of your ViewModel. To achieve this you have to clean up your ViewModelLocator as well!
You have to unregister them (Unregister<CustomerMasterViewModel>()) one by one or simply call Reset() which will unregister all viewmodels.
Then there should be no other reference to you viewmodel and the GarbageCollector can finally take care about it.
Here is an example to do so:
ViewModelLocator:
public class ViewModelLocator
{
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<CustomerMasterViewModel>();
}
public CustomerMasterViewModel CustomerMasterViewModel
{
get
{
return ServiceLocator.Current.GetInstance<CustomerMasterViewModel>();
}
}
public static void Cleanup()
{
SimpleIoc.Default.Reset();
//Don't forget to register them if the user attempts to open the new.
//The viewmodel initialization is lazy by default so this comes at no costs.
SimpleIoc.Default.Register<CustomerMasterViewModel>();
}
}
ViewModel
public class CustomerMasterViewModel : ViewModelBase
{
public CustomerMasterViewModel()
{
Messenger.Default.Register<Message>(this, this.MessageReceived);
}
#region messages
private void MessageReceived(Message obj)
{
//do something
}
#endregion
#region helper methods
public override void Cleanup()
{
base.Cleanup();
ViewModelLocator.Cleanup();
}
#endregion
}
In Short:
1) As far as i understood clean up is necessary after you're done.
2) Yes, calling the Cleanup() method in GalaSoft.MvvmLight.ViewModelBase will unregister all messages for this viewmodel.
3) No, see above.
4) Completely means it will unregister ALL registered messages.