CQRS events between multiple services - java

We have a microservice that listens for events, lets call this AuditService for now. It listens for Audit Events (AuditEvent) on rabbitmq. Any one who wants to call the AuditService needs to create and fire a AuditEvent. We have shared the AuditEvent pojo in a common module so it can be shared.
There is a event listener in the AuditService that listens for the AuditEvent from the rabbitmq queue. When we get a message we then do some processing/validation on the AuditEvent and then save it to the AuditEntry database table.
We then want to publish another event. Lets call this AuditPublishEvent. So in order to do this we create another command (AuditPublishCommand) which in turn fires theAuditPublishEvent. This event is again for the queue and any service that publishes the AuditEvent will listen for it. There will be a service to send it as an email, and another to send it as a push, etc.
At the moment what we are doing on the AuditService is
Listen for AuditEvent
|
v
Trigger AuditEvent event handler
|
v
Validate audit event and process it
|
v
Save it to the database
|
v
If save is successful then send AuditPublishEvent to queue via AuditPublishCommand
Note that the last part needs to be synchronous, meaning if the db save failed we don't want to send an email or such. This is currently done by calling the commandGateway from within the event handler in the AuditService, is it correct to call the commandGateway from the EventListener, if not what is the alternative?
The question is, is this the correct way/best practice of doing things using the Axon framework and spring?

Whether this is the best way to address the problem is hard to say, as it would require much more information about your domain.
What I can say, is that what your doing is technically allright. You mentioned you are unsure if the event published after the AuditEvent is stored is only published when the database changes are committed. That depends on how the event is published. If you use the EventBus to publish it and use the SpringAMQPPublisher, you’re safe.
If you publish it directly, this may not be the case.
Axon uses a unitOfWork to coordinate activities in different phases if processing. Handlers are called in the ‘started’ phase. A database commit is done in the phase after: ‘commit’.
If you want to be sure the message to AMQP after the commit, register a handler to the afterCommit phase. Handlers for this phase are not invoked on a rollback.
You can add the UnitOfWork as a parameter to you #EventHandler annoted method. Axon will automatically inject it for you.

Related

Java SDK Hyperledger Fabric Add commitListener

I'm trying to create a commitListener using the Java SDK to listen for commit events after submitting a transaction, although the listener is not responding.
I'm using the fabcar example.
// create a gateway connection
try (Gateway gateway = builder.connect()) {
// get the network and contract
Network network = gateway.getNetwork("mychannel");
Contract contract = network.getContract("fabcar");
FabcarCommitListener listener = new FabcarCommitListener();
network.addCommitListener(listener, network.getChannel().getPeers(), "createCar");
}
The FabcarCommitListener:
public class FabcarCommitListener implements CommitListener {
#Override
public void acceptCommit(BlockEvent.TransactionEvent transactionEvent) {
System.out.println("TX COMMITTED");
}
#Override
public void acceptDisconnect(PeerDisconnectEvent peerDisconnectEvent) {
System.out.println("peerDisconnected");
}
}
Any ideas how a commitListener works using the Java SDK?
A commit listener receives events only for a specific transaction invocation, not for all invocations of a given transaction name. Every transaction invocation has its own unique transaction ID, which you can obtain from the Transaction object prior to submitting:
https://hyperledger.github.io/fabric-gateway-java/release-2.2/org/hyperledger/fabric/gateway/Transaction.html#getTransactionId--
By default, a transaction submit will also listen for the transaction to be committed by peers so there is no need for your code to listen for transaction commits. There are several built-in strategies for determining when a transaction has been successfully committed, which you can select either:
When connecting the Gateway: https://hyperledger.github.io/fabric-gateway-java/release-2.2/org/hyperledger/fabric/gateway/Gateway.Builder.html#commitHandler-org.hyperledger.fabric.gateway.spi.CommitHandlerFactory-
For a specific transaction invocation: https://hyperledger.github.io/fabric-gateway-java/release-2.2/org/hyperledger/fabric/gateway/Transaction.html#setCommitHandler-org.hyperledger.fabric.gateway.spi.CommitHandlerFactory-
If you want to implement your own custom logic for identifying whether a transaction has committed successfully, you can write your own custom commit handler implementation, and this implementation can use a commit listener to identify the commit and connection status of all the peers you care about. Here is a sample commit handler and factory implementation that make use of commit listeners:
https://github.com/hyperledger/fabric-gateway-java/blob/release-2.2/src/test/java/org/hyperledger/fabric/gateway/sample/SampleCommitHandlerFactory.java
https://github.com/hyperledger/fabric-gateway-java/blob/release-2.2/src/test/java/org/hyperledger/fabric/gateway/sample/SampleCommitHandler.java
If you want to look at all the transactions committed to the blockchain, even if only to pick out certain ones you care about, then use a block listener:
https://hyperledger.github.io/fabric-gateway-java/release-2.2/org/hyperledger/fabric/gateway/Network.html#addBlockListener-java.util.function.Consumer-
From the block event you can navigate down through all the transactions included in the block.
Having said all this, both block listeners and commit listeners really deal with the mechanics of Fabric blockchains. So inspecting the transactions that have operated on the ledger and checking whether they were successfully committed. If you want to orchestrate business processes around transactional events then probably you should actually be using a contract event listener.
If you want to trigger some business process when a new car is created, implement your createCar transaction function so that it emits an event when it is committed:
https://hyperledger.github.io/fabric-chaincode-java/release-2.2/api/org/hyperledger/fabric/shim/ChaincodeStub.html#setEvent-java.lang.String-byte:A-
In your client application, simply listen for this event using a contract event listener:
https://hyperledger.github.io/fabric-gateway-java/release-2.2/org/hyperledger/fabric/gateway/Contract.html#addContractListener-java.util.function.Consumer-java.lang.String-
You can use checkpointing to allow your client to resume listening for events at the last processed block position after a client application restart:
https://hyperledger.github.io/fabric-gateway-java/release-2.2/org/hyperledger/fabric/gateway/Contract.html#addContractListener-org.hyperledger.fabric.gateway.spi.Checkpointer-java.util.function.Consumer-java.lang.String-

How to enable/disable JMS listener on runtime? Can I create one api which enables/disables listener on runtime?

I am working on a Problem where I need to enable/disable a JMS listener on runtime(without restarting application). I want to create a rest service which will be hit manually and it has to turn on/turn off the listener on runtime.
You should provide more information about how you are using the framework. Assuming you mean #JmsListener, you can use the registry to stop/start the listener container...
#JmsListener(id = "foo")
...
#Autowired
private JmsListenerEndpointRegistry registry;
...
registry.getListenerContainer("foo").stop();
...
registry.getListenerContainer("foo").start();
If you have control over your processing model (synchronous/asynchronous) you could choose to use synchronously getting the messages: MessageConusmer.receive(long timeout)
Then you would simply stop making this call while 'logged out' and start making this call while being logged in.
If you are forced to use async. reception (with onMessage() ) then your receive will continuously receive messages unless you stop the session with Session.close(). To restart you would have to re-create and restart the session and re-create your MessageConsumer

How to group/batch events with aggregator in spring integration

I have a channel whose payload is different POJOs that implement an interface called Event.
public interface Event {
String getEventType();
}
Events of many event types are added to channel one by one using a gateway. I want to group the events based on event type and call a service activator. The service have the following signature.
void processEventsInBatch(String eventType, List<Event> events);
It is important to get multiple events which belong to the same event type in the list to process them in batch and reduce multiple calls to external services.
How to achieve this with spring integration?
Aggregator in spring-integration uses correlation-id header (by default) to identify different messages in the same group. So the first step is to get eventType as correlation-id header. Later we can get this header as eventType param in the service activator as the correlation-id header will be present for the groups created by aggregator. This can be done by the following xml config
<int:header-enricher>
<int:correlation-id expression="payload.getEventType()"/>
<int:header-enricher>
Now the aggregator can be used as shown below.
<int:aggregator release-strategy-expression="size() >= 25"
group-timeout="5000"
expire-group-upon-completion="true"
send-partial-results-on-expiry="true" />
The above aggregator will send a group when it have at least 25 events in one group or it waited for 5 seconds. We can adjust the first two parameters to control how big we want the list to be and how much delay we want to introduce. The expire-group-upon-completion attribute is required to make sure that the aggregator continue to create new groups with same correlation-id. And the send-partial-results-on-expiry is required to make sure that if we get less than 25 events in 5 seconds, then the aggregator will send a group with what it have.

How to start Spring JMS listener container manually

I have a server side application that consumes message from an JMS queue. I use Spring listener container like this:
<jms:listener-container connection-factory="myConnectionFactory"
..........
concurrency="4-8">
<jms:listener id="myListener" destination="my.ems.queue" ref="listenerBean" method="method"/>
</jms:listener-container>
This works fine.
One problem of this is that the listener starts to consume JMS message as soon as it is setup. However, some of the beans the listenerBean depends take some time to initialize (It needs to populate some data from database).
Therefore, if the service starts up with some pending JMS message in the queue, it will try to serve it before data is populated completed. This causes some error.
My question is that how can I not start listener automatically until a later stage when data is fully populated, so that I can call the start() method to manually start it?
You can set the autoStartup property on DMLC to keep it from starting until you choose to call start().
Another way is to make sure the connection factory is not created before your other dependent beans are ready.
<bean class="..." name="myConnectionFactory" depends-on="importantOtherBean"/>

callback function do background jobs after the completing the action in java spring

I am new to Java Spring Framework, I am Rails developer I have requirement in java spring like I need to do background jobs but after the response send to the end User. It should not wait for the jobs to complete. But the jobs should run every time action completes.
Is a webservice app. We have Service, Bo and DAO layers and we are logging any exceptions occurred while processing the user data in database before response send to user, but now we want to move(Exception handling) after response send to user to increase the performance.
I remember in rails we have callbacks/filters after the action executed it calls the methods we want to executed. Same is available in java Spring?
Thanks,
Senthil
I assume the use case is something like a user requests a long-running task, and you want to return a response immediately and then launch the task in the background.
Spring can help with this. See
http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/scheduling.html
In particular see the #Async annotation.
With respect to the client getting a response back following the async processing (exception or otherwise), you can do it, but it's extra work.
Normally the immediate response would include some kind of ID that the client could come back with after some period of time. (For example, when you run a search against the Splunk API, it gives you a job ID, and you come back later with that job ID to check on the result). If this works, do that. The client has to poll but the implementation is the simplest.
If not, then you have to have some way for the client to listen for the response. This could be a "reply-to" web service endpoint on the client (perhaps passed in with the original request as a custom X-Reply-To HTTP header), or it could be a message queue, etc.

Categories

Resources