Retrieving data from database using spring integration JDBC without poll - spring

Currently learning spring integration, I want to retrieve information from a MySQL database to use inside an int:service-activator, or an int:splitter .
Unfortunately, it would seem that most examples and documentation is based around the idea of using an int-jdbc:inbound-channel-adapter, which in itself requires a poller. I don't want to poll a database, but rather retrieve specific data based on the payload of an existing message originating from an int:gateway. This data would then be used to further modify the payload, or assist in how the message is split.
I tried using int-jdbc:outbound-gateway, as the description states:
... jdbc.JdbcOutboundGateway' for updating a database in response to a message on the request channel, and/or for retrieving data from the database ...
This implies that it can be used for retrieval of data only and not just updates, but as I implement it, there's a complaint that at least one update statement is required:
And so I'm currently sitting with a faulty prototype that initially looks like so:
The circled piece being the non-functioning int-jdbc:outbound-gateway.
My end goal is to, based on the payload coming from the incomingGateway (in the picture above), retrieve some information from a MySQL database, and use that data to split the message in the analyzerSplitter, or to perhaps modify the payload using an int:service-activator. This should then all be linked up to a int-jdbc:message-store which I believe could assist with performance. I do not wish to poll the database on a regular basis, and I do not wish to update anything in the database.
By testing using the polling int-jdbc:inbound-channel-adapter, I am confident that my datasource bean is set up correctly and the query can execute.
How would I go about correctly setting up such behaviour in spring integration?

If you want to proceed with the flow after updating the database, you can simply use a JdbcTemplate in a method invoked by a service activator, or, if it's the end of the flow, use an outbound channel adapter.
The outbound channel adapter is the inverse of the inbound: its role is to handle a message and use it to execute a SQL query. By default, the message payload and headers are available as input parameters to the query, as the following example shows:
...

Related

Atomically update database and send message. Outbox pattern or not?

You have a command/operation which means you both need to save something in database end send an event/message to another system. For example you have an OrderService and when a new order is created you want to publish an "OrderCreated"-event for another system/systems to react on (either direct message or using a message broker) and do something.
The easiest (and naive) implementation is to save in db and if successful then send message. But of course this is not bullet proof because the other service/message broker is down or your service crash before sending message.
One (and common?) solution is to implement "outbox pattern", i.e. instead of publish messages directly you save the message to an outbox table in your local database as part of your database transaction (in this example save to outbox table as well as order table) and have a different process (polling db or using change data capture) reading the outbox table and publish messages.
What is your solution to this dilemma, i.e. "update database and send message or do neither"? Note: I am not talking about using SAGAs (could be part of a SAGA though but this is next level).
I have in the past used different approaches:
"Do nothing", i.e just try to send the message and hope it will be sent. Which might be fine in some cases especially with a stable message broker running on same machine.
Using DTC (in my case MSDTC). Beside all the problem with DTC it might not work with your current solution.
Outbox pattern
Using an orchestrator which will retry process if you have not got a "completed" event.
In my current project it is not handled well IMO and I want to change it to be more resilient and self correcting. Sometimes when a service is calling another service and it fails the user might retry and it might work ok. But some operations might require out support to fix it (if it is even discovered).
ATM it is not a Microservice solution but rather two large (legacy) monoliths communicating and is running on same server but moving to a Microservice architecture in the near future and might run on multiple machines.

Elastic APM - Creating Transaction / Span using traceparent / trace_id in C# Agent Libraries

I'm trying out the .Net agent in Elastic APM and I'm using a C# application which is created using a framework called ASP.net Boilerplate. I've added the core libraries as mentioned in the documentation and added the settings in appsettings.json. This enables the default instrumentation and I got traces in the APM visualized through Kibana.
Currently I've got a node.js application running and I publish a message to a RabbitMQ queue with the traceparent in the message payload. The C# app reads the published message. I need to create a transaction or span using this traceparent / trace id so that Kibana would show the trace among the distributed systems.
I want to know if there is a way to create a transaction (or span) using a traceparent that is being sent from another system not using a HTTP protocol. I've checked the Elastic APM agent documentation -> Public API for information but couldnt find any information on this. Is there a way? Thanks.
I want to know if there is a way to create a transaction (or span) using a traceparent that is being sent from another system not using a HTTP protocol.
Yes, this is possible and there is an API for it. This part of the documentation explains it.
So you'll need to do this when you start your transaction - I imagine in your scenario this will be when you read a message from RabbitMQ.
When you start the transaction there is an optional parameter called distributedTracingData - if you pass it, then the transaction will reuse the traceid which you passed through RabbitMQ, and this way the new transaction will be part of the whole trace. If you don't pass this parameter, a new traceid will be generated and a new trace will be started.
Another comment that may help: you pass the trace id into the method where you start the transaction and each span will inherit this trace id within a transaction - so you control this on the transaction level and accordingly you don't pass it into a span.
Here is a small code snippet on how this would look:
serializedDistributedTracingData = //read this from the message which you get RabbitMq
var transaction2 = Agent.Tracer.StartTransaction("RadFromQueue", "RabbitMQRead",
DistributedTracingData.TryDeserializeFromString(serializedDistributedTracingData));
#gregkalapos, again thank you for the information. I checked how to acquire the neccessary trace information as in node.js agent documentation and when I debugged noticed that it was the trace id. Next in the C# consumer end I placed a code snippet as mentioned in the .Net agent and gave it a run. Kibana displayed the transactions from two different services in a single trace as I hoped it would.

How to log all microservices logs in a single Log-file using springboot

I have 5 web applications which I developed using Springboot(A,B,C,D and E).
Below are the flow of 2 calls
First Flow:
A's Controllers --> A's Service --> B's Controller --> B'Service --> C's Controller --> C's Service --> C's Dao --> DB
SecondFlow:
A's Controllers --> A's Service --> D's Controller --> D'Service --> B's Controller --> B'Service --> C's Controller --> C's Service --> C's Dao --> DB
Once fetch/push data from/into the DB then the corresponding methods are returning some value. For each and every method logging the status (input details and returning status). I am able to see logs in each service separately. But I want to see complete one request-response(A's controller request to A's controller response) cycle logs in one file.
How Can I achieve it?
This is a ver bad idea, but let's take a step back and look at the problem instead of guessing a solution.
You have multiple applications that collaborate together to execute (distributed) transactions. You need to trace those interactions to see your dataflow. This is very useful for many reasons so it's correct that you care about it. It is also correct to collect all you log entries in a single sink, even if it won't be a file because it is not well suited to manage prodcution workloads. A typical scenario that many organization implements is the following
Each application send logs to files or standard output
For each node of you infrastructure there is an agent that reads that streams, does some basic conversion (eg. translates log entries in a common format) and send data to a certain sink
The sink is a database, the best technology option is a DBMS without strict requirements about data schema (you are storing everything in a single huge table after all) and transactional properites (if the data are logs, you are fine with an optimistic concurrency control). You also want some tool that is more good at reads than writes and have good performance in complex searches to drill down a large amount of structured data
a Dashboard to read logs, make searches and even create dashboard with synthetic stats about events
BONUS: use a buffer to manage load spikes
There are precise tools to do the job and they are
logstash/beats/fluentd
Elasticsearch....what else? ;)
Kibana, the favourite Elasticsearch client
BONUS: rabbimq/kafka/otherMessageBroker or Redis
but you still miss a step
Suppose you call a REST API, something simple like a POST /users/:userId/cart
API Gateway receives your request with a JWT
API Gateway calls Authentication-service to validate and decode the JWT
API Gateway calls Authorization-service to check if the client as right to perform the request
API Gateway calls User-service to find :userId
User-Service calls Cart-service to add the product on :userId cart
Cart-Service calls Notification-Service to decide whether is needed to send a notification for the completed task
Notification-Service calls Push-Gateway to invoke an external push notification service
....and back
to not get lost in this labyrinth you NEED just one thing: the correlation ID
Correlation IDs attach a unique ID to all interaction beetween these microservices (headers in HTTP calls or AMQP messages, for instance) and your custom log library (because you've already built a custom logging library and shared it among all the teams) capture this ID to include it in every log entry wrote in the context of the single request processed from each of those microservices. You can even add that correlation ID in the client response, catch it if the respone carry out an error code and perform a query on your logs DB to find all the entries with the given correlation ID. If the system clock works, they will be retrieved in the correct time order and you will be able to reconstruct the dataflow
Distributed Systems make everything more complicate and add a lot of overhead on things that we ever done before, but if you put in your pocket the right tools to manage the complexity, you can see the benefits
you can implement central logging system like:
The ELK stack (Elastic Search, Logstash and Kibana) for Centralized Logging.

Preventing data loss in client authoritative database writes

A project I'm working on requires users to insert themselves into a list on a server. We expect a few hundred users over a weekend and while very unlikely, a collision could happen in which two users submit the list concurrently and one of them is lost. The server has no validation, it simply allows you to get and put data.
I was pointed in the direction of "optimistic locking" but I'm having trouble grasping when exactly the data should be validated and how it prevents this from happening. If one of the clients reads the data, adds itself and then checks again to ensure that the data is the same with the use of an index or timestamp, how does this prevent the other client from doing the same and then one overwriting the other?
I'm trying to understand the flow in the context of two clients getting data and putting data.
The point of optimistic locking is that the decision to accept or reject a write is taken on the server, and is protected against concurrency by a pessimistic transaction or some sort of hardware protection, such as compare-and-swap. So a client requests a write together with some sort of timestamp or version identifier, and the server only accepts the write if the timestamp is still accurate. If it isn't the client gets some sort of rejection code and will have to try again. If it is, the client gets told that its write succeeded.
This is not the only way to handle receiving data from multiple clients. One popular alternative is to use a reliable messaging system - for example the Java Messaging Service specifies an interface for such systems for which you can find open source implementations. Clients write into the messaging system and can go away as soon as their message is accepted. The server reads requests from the messaging system and acts on them. If the server or the network goes down it's no big deal: the messages will still be there to be read when they come back (typically they are written to disk and have the same level of protection as database data although if you look at a reliable message queue implementation you may find that it is not, in fact, built on top of a standard database table).
One example of a writeup of the details of optimistic locking is the HTTP server Etag specification e.g. https://en.wikipedia.org/wiki/HTTP_ETag

Inconsistent Behavior in SOA Composite/BPEL

I'm working on a BPEL process that includes an email service, and is generally kicked off by an AQ Adapter. The composite pulls email addresses from a DVM lookup and from the content returned by a service invoke.
My code that assigns the email addresses looks something like this:
concat(bpws:getVariableData('EmailVariable'),',',bpws:getVariableData('ServiceOutputVariable, 'ServiceVariablePart','Email')
Where "EmailVariable," is two comma separated addresses and "Email," is a single email address
When BPEL is called via the AQ Adapter, the "to" line of the email comes back as EmailA,EmailBEmailC.
When I wired it to a file adapter for debugging, though, the "to" line reads "EmailA,EmailB,EmailC" (The desired result, obviously).
The only thing that changed from the AQ adapter version to the File Adapter version is the source of the kickoff value.
What could be causing this inconsistent behavior?
Obvious first question is have you posted this in the Oracle SOA forum or searched oracle.support to see if it is a bug?
Anyway, put a mediator between the AQ interface and BPEL and have the mediator resolve the issue, through data transformation, which is its purpose in the first place and best practice design pattern: isolate your service implementation from the service interface.

Resources