Grails: Event listener never stop (with websocket plugin) - mongodb

I have a problem with my listener (platform core plugin). It never stop after event (afterInsert) was triggered (Mongo standalone)
My service catch the event and use the SimpMessagingTemplate (websocket plugin) to send on topic the data (A news user registration). The data is saved, but the listener is triggered again and again.
p.s. The data not really saved, the consequent exception, rollback the transaction. But in debug mode I can see the assigned id.
#Transactional
class MessageEventService {
SimpMessagingTemplate brokerMessagingTemplate
#Listener(topic = 'afterInsert',namespace = 'gorm')
void afterInsert(User user) {
log.info("DIOBO")
brokerMessagingTemplate.convertAndSend("/topic/myEventTopic", "myEvent: User Add ${user.name}")
}
}
And at the end...
.[grails] Servlet.service() for servlet grails threw exception
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2367)
Why happens?!?!?
Thanks!

Related

Vertx not able to handle internal code error to client automatically

I have a verticle which accepts REST request, get data from other verticle through event bus and respond back to client.
vertx.exceptionHandler(event -> logger.error("Vertx exception ", event));
router.get("/api/v1/:param").handler(this::routerHandler);
public void routerHandler(RoutingContext rc) {
vertx.eventBus().request("data", param,
result -> {
if (result.succeeded()) {
logger.info("Request handled successfully");
// intentionally creating exception body() will return String
JsonObject jsonObject = (JsonObject) result.result().body();
rc.response().end(jsonObject)
}else{
logger.error("Request failed");
}
}
When a exception is raised it is printed in exception handler that I setup in vertx instance but after that the vertx is not reporting back the exception immediately to client instead it waits for timeout(30 secs) to occur.
I tried attaching error handler to router object and failure handler to route object but nothing helps to report the exception immediately to client. I know I can have a try catch and report the error in catch block. But I want know if there is any other way to handle this like Servlet or Spring MVC reports back to client even though the exception is not handled in code.
router.errorHandler(500,routingContext -> {
System.out.println(routingContext.failed());
routingContext.response().end("Exception ");
});
router.route().handler(BodyHandler.create()).failureHandler(routingContext -> {
Uncaught exceptions are reported to the context exceptionHandler. By default it prints the exception to the console.
You can configure it but you will not get a reference to the corresponding HTTP request anyway (the exception may come from different things).
Most problems like this are usually found during unit/integration/acceptance testing.
And for the remainders you could set a timeout handler on your router definition to make sure the request is ended before the default 30 seconds.
If you don't want to miss any uncaught exception, you should switch to the Vert.x Rxified API. When using RxJava, any exception thrown will be reported to the subscriber.

How shutdown KafkaListener when error occurs

I wrote a Listener in this way
#Autowired
private KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry;
#KafkaListener(containerFactory = "cdcKafkaListenerContainerFactory", errorHandler = "errorHandler")
public void consume(#Payload String message) throws Exception {
...
}
#Bean
public KafkaListenerErrorHandler errorHandler() {
return ((message, e) -> {
kafkaListenerEndpointRegistry.stop();
return null;
});
}
In #KafkaListener annotation I specified my error handler that simply stop the consumer.
It seems to work but I've some question to ask.
Is there a built-in errorHandler for this scope? I've read that ContainerStoppingErrorHandler can be use, but I cannot set it because #KafkaListener's errorHandler accept beans of KafkaListenerErrorHandler type.
I see that with kafkaListenerEndpointRegistry.stop(); do a graceful stop. So before stopping the partition offset of the consumed message is committed.
What I would know is what happen when kafkaListenerEndpointRegistry.stop(); is called and before listener is definitely turned off another message arrive into the topic?
Is this message consumed?
I image this scenario
time0: kafkaListenerEndpointRegistry.stop() is called
time1: a message is pushed into the listened topic
time2: kafkaListenerEndpointRegistry.stop() complete graceful stop
I'm worried about a possible message arrive at time1. What would happen in this scenario?
Do not stop the container within the listener.
ContainerStoppingErrorHandler is set on the container factory, not the annotation.
If you are using Spring Boot, just declare the error handler as a bean and boot will wire it in.
Otherwise add the error handler to the connection factory bean.
With this error handler, throwing an exception will immediately stop the container.

How to handle commands sent from saga in axon framework

Using a saga, given an event EventA, saga starts, it sends a command (or many).
How can we make sure that the command is sent successfully then actual logic in other micro-service did not throw, etc.
Let's have an example of email saga:
When a user register, we create a User Aggregate which publishes UserRegisteredEvent, a saga will be created and this saga is responsible to make sure that registration email is sent to user (email may contain a verification key, welcome message, etc).
Should we use :
commandGateway.sendAndWait with a try/catch -> does it scale?
commandGateway.send and use a deadline and use some kind of "fail event" like SendEmailFailedEvent -> requires to associate a "token" for commands so can associate the "associationProperty" with the correct saga
that sent SendRegistrationEmailCommand
commandGateway.send(...).handle(...) -> in handle can we reference eventGateway/commandGateway that were in MyEmailSaga?
If error we send an event? Or can we modify/call a method from the saga instance we had. If no error then other service have sent an event like "RegistrationEmailSentEvent" so saga will end.
use deadline because we just use "send" and do not handle the eventual error of the command which may have failed to be sent (other service is down, etc)
something else?
Or a combination of all?
How to handle errors below? (use deadline or .handle(...) or other)
Errors could be:
command has no handlers (no service up, etc)
command was handled but exception is raised in other service and no event is sent (no try/catch in other service)
command was handled, exception raised and caught, other service publish an event to notify it failed to send email (saga will receive event and do appropriate action depending on event type and data provided -> maybe email is wrong or does not exist so no need to retry)
other errors I missed?
#Saga
public class MyEmailSaga {
#Autowired
transient CommandGateway commandGateway;
#Autowired
transient EventGateway eventGateway;
#Autowired
transient SomeService someService;
String id;
SomeData state;
/** count retry times we send email so can apply logic on it */
int sendRetryCount;
#StartSaga
#SagaEventHandler(associationProperty = "id")
public void on(UserRegisteredEvent event) {
id = event.getApplicationId();
//state = event........
// what are the possibilities here?
// Can we use sendAndWait but it does not scale very well, right?
commandGateway.send(new SendRegistrationEmailCommand(...));
// Is deadline good since we do not handle the "send" of the command
}
// Use a #DeadlineHandler to retry ?
#DeadlineHandler(deadlineName = "retry_send_registration_email")
fun on() {
// resend command and re-schedule a deadline, etc
}
#EndSaga
#SagaEventHandler(associationProperty = "id")
public void on(RegistrationEmailSentEvent event) {
}
}
EDIT (after accepted answer):
Mainly two options (Sorry but kotlin code below):
First option
commandGateway.send(SendRegistrationEmailCommand(...))
.handle({ t, result ->
if (t != null) {
// send event (could be caught be the same saga eventually) or send command or both
}else{
// send event (could be caught be the same saga eventually) or send command or both
}
})
// If not use handle(...) then you can use thenApply as well
.thenApply { eventGateway.publish(SomeSuccessfulEvent(...)) }
.thenApply { commandGateway.send(SomeSuccessfulSendOnSuccessCommand) }
2nd option:
Use a deadline to make sure that saga do something if SendRegistrationEmailCommand failed and you did not receive any events on the failure (when you do not handle the command sent).
Can of course use deadline for other purposes.
When the SendRegistrationEmailCommand was received successfully, the receiver will publish an event so the saga will be notified and act on it.
Could be an RegistrationEmailSentEvent or RegistrationEmailSendFailedEvent.
Summary:
It seems that it is best to use handle() only if the command failed to be sent or receiver has thrown an unexpected exception, if so then publish an event for the saga to act on it.
In case of success, the receiver should publish the event, saga will listen for it (and eventually register a deadline just in case); Receiver may also send event to notify of error and do not throw, saga will also listen to this event.
ideally, you would use the asynchronous options to deal with errors. This would either be commandGateway.send(command) or commandGateway.send(command).thenApply(). If the failure are businesslogic related, then it may make sense to emit events on these failures. A plain gateway.send(command) then makes sense; the Saga can react on the events returned as a result. Otherwise, you will have to deal with the result of the command.
Whether you need to use sendAndWait or just send().then... depends on the activity you need to do when it fails. Unfortunately, when dealing with results asynchronously, you cannot safely modify the state of the Saga anymore. Axon may have persisted the state of the saga already, causing these changes to go lost. sendAndWait resolves that. Scalability is not often an issue, because different Sagas can be executed in parallel, depending on your processor configuration.
The Axon team is currently looking at possible APIs that would allow for safe asynchronous execution of logic in Sagas, while still keeping guarantees about thread safety and state persistence.

Implementing transaction in EJB with javax.transaction.UserTransaction

I am implementing an EJB application. At this point I need a transaction. I need to execute 3 methods in row and if one fails, everything should be rolled back.
Here: http://www.conceptgo.com/gsejb/eb04.html, I have found a tutorial.
My code:
try {
javax.transaction.UserTransaction ut = (UserTransaction) ctx.lookup("java:comp/UserTransaction");
ut.begin();
Feeds feed = loadFeed(url);
try{
em.persist(feed);
uf.setFeedId(feed.getFeedId());
uf.setUserId(user_id);
em.persist(uf);
}catch (EntityExistsException e){
ut.rollback();
return false;
}catch (IllegalArgumentException ea){
ut.rollback();
return false;
}
if (feed.getFeedId()!= null && feed!=null) {
ut.commit();
}else{
ut.rollback();
return false;
}
When I run my app I get next error message:
Caused by: java.lang.IllegalStateException: BaseTransaction.checkTransactionState
- ARJUNA016051: thread is already associated with a transaction
Anyone knows what's the cause and how to solve it?
The error means that you already have a transaction in progress, more than likely a container managed transaction.
What does your bean/method look like? The default transaction behavior for a stateless session bean in JBoss7 is that it executes with Container managed transaction and with 'Required' transaction attribute.
So assuming that container managed transactions work for you, you don't need the UserTransaction. So you can remove the lookup and the begin/commit/rollback since that will be managed for you.
If you do want to manage transactions yourself, then mark the bean as using Bean managed transactions and then you can begin/commit/rollback the UserTransaction. To mark a bean as using bean managed transactions, you will apply the annotation #TransactionManagement(TransactionManagementType.BEAN) to the class or method.
As error shows you are try to interrupt container managed transaction in JBoss. If you want to deal with transaction with own way then change your class/method bean managed like.
#TransactionManagement(TransactionManagementType.BEAN)
public void getTransaction(){
//....
}
Now you are safe from JBoss end but ensure you have to define each step of transaction in Bean managed Transaction.
It is not advisable to use few steps for CMT and few steps for BMT because in case CMT container will responsible for handling transaction and associated thread. So ejb container will acquire lock on objects participated in transaction and will not be released until transaction completed these objects may cause of problem if you need it in BMT. So you have to either use CMT or BMT .

Newly Created & Loaded StatefulKnowledgeSession - JBPM 5

*strong text*What could be the problem if the task-completed event is not getting dispatched to the StatefulKnowledgeSession ?
For a new process-instance, I do
create a new session
register human-task local GenericHTWorkItemHandler
register custom event listeners
call startProcess(processDefinitionId,parameters);
It starts a new instance, creates the first human-task via the registered human-task-handler.
When I want to complete the human-task, I do
restore the KnowledgeSession with
JPAKnowledgeService.loadStatefulKnowledgeSession(lastSessionId,kBase,null,
env);
again register human-task local GenericHTWorkItemHandler
again register custom event listeners
Then call taskService.completeTask, BUT the task-completed is not dispatched to the KnowledgeSession. And the process-flow is not happening
Should I not register the event listeners again ?
Should I not register the work-item-handlers again ?
Update 1
Exception trace:
07:52:09,618 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/workflow-console].[rsservlet]] (http--0.0.0.0-8280-15) Servlet.service() for servlet rsservlet threw exception: java.lang.IllegalStateException: EntityManager is closed
at org.hibernate.ejb.AbstractEntityManagerImpl.joinTransaction(AbstractEntityManagerImpl.java:1158) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
at org.drools.container.spring.beans.persistence.DroolsSpringJpaManager.getApplicationScopedPersistenceContext(DroolsSpringJpaManager.java:89) [drools-spring-5.5.0.Final.jar:5.5.0.Final]
at org.drools.persistence.SingleSessionCommandService.execute(SingleSessionCommandService.java:350) [drools-persistence-jpa-5.5.0.Final.jar:5.5.0.Final]
at org.drools.command.impl.CommandBasedStatefulKnowledgeSession.getEnvironment(CommandBasedStatefulKnowledgeSession.java:478) [drools-core-5.5.0.Final.jar:5.5.0.Final]
at org.jbpm.process.workitem.wsht.GenericHTWorkItemHandler$TaskCompletedHandler.handleCompletedTask(GenericHTWorkItemHandler.java:260) [jbpm-human-task-core-5.4.0.Final.jar:5.4.0.Final]
at org.jbpm.process.workitem.wsht.GenericHTWorkItemHandler$TaskCompletedHandler.execute(GenericHTWorkItemHandler.java:234) [jbpm-human-task-core-5.4.0.Final.jar:5.4.0.Final]
at org.jbpm.task.service.local.LocalTaskService$SimpleEventTransport.trigger(LocalTaskService.java:329) [jbpm-human-task-core-5.4.0.Final.jar:5.4.0.Final]
When reloading a session I am registering new HumanTaskWorkItemhandlers.It keeps on registering event handlers with the TaskService.
When I connect the workItemHandlers, they register eventHandlers with the taskService.
When will this eventHandlers get de-registered from the taskService ?
If you are using a task service, it will by default dispatch events to all listeners. So that means multiple ksessions can receive the event (but a task completion event should only be processed by one ksession). As you mentioned, using owningKSessionOnly can be used to make sure only one ksession will react to the completion event.
You can deregister the listeners of the handler by calling dispose on the handler.