I have a requirement in my java web application where I need to send email alerts for certain conditions. For this I have used javax mail api and sending email works just fine. But the problem is the programs executions waits until the methods for sending the email are executed. As there are hundreds of email to be sent at various points ... this reduces the performance significantly.
I am using spring and have also used spring aop. Can anyone suggest me how can I separate my business logic and sending email functionality. It should be like -
Sending emails is my advice which gets executed when xyz method is called - So main execution should not wait for advice to finish its execution rather it should return back and execute further business logic thus email sending executed separately.
Here creating new threads seems obvious choice. But I think there could be some better way, is there? Thanks.
You can make the mail sending method #Async. This way Spring will execute this in a seperate thread. Read this blog post about it: Creating Asynchronous Methods
What you describe is asynchronous execution and natural way to do async execution is Java is to use threads.
You can introduce some Executor, e.g., Executors.newFixedThreadPool(), and use it to offload mailing task into separate threads.
Aspect itself is a unsuitable place for this, since this would introduce state into aspect, for example, you may want to check if mail task was successful by using returned Future:
class Mailer {
private final ExecutorService executor = Executors.newFixedThreadPool(maxMailingThreads);
//...
public void doMail(MailTask anEmail) {
Future<MailTaskResult> future = executor.submit(new MailTask(anEmail));
future.get().isSuccessful(); // handle success or failure somehow
}
Better move this logic into separate class and call it from aspect somehow.
Treat the email sending functionality like an IO device. Make it a plugin to your business logic. Do not allow any knowledge of the fact that you're even talking to the email code into your business logic. Make the email logic depend on the business logic. Never the other way around.
Here's a very good talk about this kind of architecture:
https://vimeo.com/97530863
Here's a series debating it:
https://www.youtube.com/watch?v=z9quxZsLcfo
Here's a ruby master demonstrating it with real code. We miss him.
https://www.youtube.com/watch?v=tg5RFeSfBM4
If your business rules are interesting enough to be worth respecting than this is the way to make them the masters of your application. Express them only using java. Don't accept any help. No spring, no weird annotations, just business rules. Push all that "help" out to the mail code.
Do this and your app will scale well. I think this is the best way to put it:
That's from a hexagonal architecture post. But the idea of giving your business rules a safe place to live removed from implementation detail shows up in many architectures. This answer rounds them up nicely.
Use a localhost MTA (like OpenSMTPD) and then relay to your real SMTP server, like Amazon SES ("Satellite" mode). It won't block.
I did a test, and sent 1000 emails in 2.8 seconds this way
It's simpler than doing async in java, and is useful across multiple applications.
As for separating logic, raise a Spring Application Event when needed, and make another class to listen to it, and send your email from there. Or consider something like Guava's EventBus
Consider creating a separate thread to send emails within your application. This will allow parallel execution(application+email sending).
If you would want another approach you can create a separate back end application that only sends emails. Although you will need to submit the email messages to the application. An asynchronous way to do this is to send a JMS message to the email application.
Related
I am new to Microservices. I am currently developing an application using Microservices and using both synchronous and asynchronous communication.
Recently I have read many articles saying that you shouldn't use synchronous(HTTP) communication and should only use asynchronous(message broker). A few have mentioned - If the Microservices are communicating via REST, then you still have, in effect, a monolithic application.
Consider a scenario where we have 2 Microservices (MS) :
CurrencyConversion MS - We will pass input to this MS as we want to convert $100 to INR. CurrencyConversion MS will execute a GET call to CurrencyExchange MS to get exchange rate for $ to INR.
CurrencyExchange MS - We will pass input to this MS as $ to INR and CurrencyExchange MS will return the exchange rate as 75 i.e. $1 = 75 INR.
In such cases, CurrencyConversion can't work independently and if CurrencyExchange is failing, CurrencyConversion is also going to fail.
So my first question is - Is synchronous communication between services an anti-pattern in Microservices?
The second question is - If synchronous communication is not a preferred way then what is the best way to design communication between different internal services where one service is going to execute a GET call to get some dependent data for example the scenario I have mentioned above.
How do we overcome this without using synchronous communication?
When you are on a microservices project, it is very frequent that microservices need other microservices. As you said, there are several ways to communicate between them: synchronously or asynchronously.
For my part, I think that there is no good or bad choice between synchronous and asynchronous, what you need to do is to choose what best meets your needs.
In the case you mention, I would personally choose a synchronous HTTP call simply because if you made an asynchronous call, it would be more difficult to know if your MS has received the request and especially when it will answer it. This could force you to block the call from your client for a while because he is calling you synchronously in HTTP on a REST resource.
However, if your client does not expect an immediate response to his call, you can very well start with an asynchronous call and provide a notification system to inform your client that the response to his request is ready.
In any case, synchronous calls between microservices should not be considered as anti-patterns. Synchronous and asynchronous calls each meet different needs, so you have to choose which one is more appropriate in your case.
Finally, whether you do synchronous or asynchronous, there are still several ways to do it. Here is a link that explains, I think, quite well the different possibilities for these two solutions : https://dzone.com/articles/patterns-for-microservices-sync-vs-async
Synchronous communication between services is not an anti-pattern in Microservices. But it's important to choose a appropriate communication style depending on the specified quality requirements. Microservices.io describes some communication patterns with pros & cons, tradeoffs and examples.
In such cases, CurrencyConversion can't work independently and if CurrencyExchange is failing, CurrencyConversion is also going to fail.
In your example the two MS are highly coupled cause they need to work together in a synchronous transaction to answer the user request. Assuming that the user wants a response within a specific time interval (lets say 50ms), synchronous communication seems appropriate. Cascading errors can be counteracted with resilience patterns (circuit breaker, bulk head, etc.). In my opinion the example functionality should get deployed in just one MS (Currency-Service). The two described operations and the underlaying domain model seem highly cohesive. That's a strong signal you should not split the functionality into multiple MS. Communication problems solved :)
I have an application which reads from a kafka queue and and goes on like this.
validate->convert->enrich->persist->notify
In the flow, I'm gathering some performance and other data points into a ThreadLocal container.
In the happy scenario I'm sending these information to a service to be later used in reporting. But the pipeline can stop in any step if one of the step fails due to a known error (eg, convert failed so flow should stop there). I do not like each of these processors to have a code that sends the information in the ThreadLocal to reporting service if the execution resulted in error, as that would couple those services with information not related to its task.
It would be nice to have a way to execute a service at the end of the flow to send this information out, no matter which step the pipeline stops moving forward. Also there could be scenarios some code did throw an exception that was not known or other issue that break the flow.
Is there a way that a final operation to be executed no matter the result of the pipeline so that it can be used to send this information similar to a finally block in java?
The integration flow is like a simple Java try...catch...finally. It is really more about a distributed computation and loosely-coupling principle between components. So, even if you tie endpoints with channels in between, there really have nothing to know about the previous and next step: everything is done in the current endpoint with its input and output channels. Therefore your request about something like finally in the flow does not fit to the EIP concepts and cannot be implement as some primitive in the framework.
You are just lucky in your use-case that you can rely on the ThreadLocal for your flow logic, but you should keep in mind that it is not a way to deal with messaging. It really has to be stateless and have scope only of the message traveling from one endpoint to another. Therefore it might be better to revise your logic in favor of storing such a tracing information into headers of that message on each step. This way in the future you can make the flow fully async or even distributed in the network.
This is just my concern for a design you have so far.
For the current error handling problem consider to have that "final" step behind some well-know channel, so you will be free to send a message to that endpoint from whatever place you need. For example you can wrap problematic endpoints into an ExpressionEvaluatingRequestHandlerAdvice. Handle an error over there and send it to the mentioned channel. This way your business method will be free from error handling and so. See more in docs: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints.html#expression-advice
If your flow starts from some gateway or inbound channel adapter, you can have an errorChannel configured there to be able to catch all the downstream errors in one central place. And again: send the handling result to the mentioned channel.
But no. No finally in the framework at the moment and I doubt it would even be suitable in the future. For the messaging and async reason I explained before.
I have to coordinate 5 separate microservices e.g. A,B,C,D,E
I need to create a coordinator which might monitor a queue for new jobs for A. If A completes ok then a rest request should be sent to B then if everything is ok (happy path) then C is called all the way down to E.
However B,C etc might fail for one reason or another e.g. end point is down or credentials are insufficient causing the flow to fail at a particular stage. I'd like to be able to create something that could check the status of failed job and rerun again e.g. lets try B again, ok now it works the flow would then continue.
Any tips or advice for patterns / frameworks to do this. I'd like something fairly simple and not over complex.
I've already looked briefly at Netflix Conductor / Camunda but ideally I'd like something a bit less complex.
Thanks
W
Any tips or advice for patterns / frameworks to do this. I'd like something fairly simple and not over complex.
What you describe is the good ol' domain of A,B,C,D and E. Because the dependencies and engagement rules between the letters are complex enough, it's good to create a dedicated service for this domain. It could be as simple as this overarching service just being triggered by queue events.
The only other alternative is to do more on the client side and organize the service calls from there. But that isn't feasible in every domain for security reasons or other issues.
And since it sounds like you already got an event queue going, I'll not recommend one (Kafka).
One way apart from Camunda, Conductor is to send a event from Service A on some Messaging Queue (eg. lets say kafka ) which provides at least once delivery semantics.
Then write a consumer which receive the event and do the orchestration part (talking to service B,C,D,E).
As these all operations needs to be idempotent.First before starting orchestration create a RequestAgg. for the event from A and keep updating its state to represent where you reach in your orchestration journey.
Now even if the other services are down or your node goes down. This should either reach the end or you should write functions to rollback as well.
And to check the states and debug , you could see the read model of RequestAgg.
My server requires sending emails pretty frequently. The emails are heavy; they have attachments as well as inline images in them.
My present code blocks code until an email is sent. (loosing 5 to 6 seconds for every email)
What is the best approach for handling the emails with out blocking the main code flow?
If you are suggesting threads, please elaborate on how efficiently it could be handled?
There are multiple ways to achieve this functionality.
Synchronous Call
This is the one which you are already using. Code (synchronously) invokes Java Mail API and waits for API to complete the execution. The process may take time depending on the complexity of building the email message (fetching records from Database, reading images/documents (attachments), communication with Mail Server etc.
Trade-offs
For individual requests(web/desktop), response latency will increase based on the time it takes to construct and send email.
An exception in sending email, may require redo of entire process (if retried).
Transactional data (e.g. DB) may be rolled back, due to exception while sending email. This may not be desired behavior.
Overall application latency will increase, if similar functionality is invoked by multiple users concurrently.
Email retry functionality may not be possible, if email sending code is tightly coupled with other functional code.
Multithreading Approach
Create a separate thread to asynchronously send an email. Calling code need not have to wait for Email send functionality to complete and execute rest of the code. Ideally, should make use of ThreadPool, instead of blandly creating new threads.
Trade-offs
Though, request latency will go down, it is still not reliable. Any exception occurred while constructing/sending email may result into, no email sent to user.
Email sending functionality can't be distributed across multiple machines.
Retry functionality is possible, since email code is separated into separate class. This class can be independently called, without a need of redoing other things.
Asynchronous Processing
Create a class, which accepts Email request and stores it in either database or messaging infrastructure (e.g. JMS). The message listeners will process the task as and when it arrives and update the status against each task.
Trade-offs
Email requests can be processed in distributed mode.
Retry email possible, without having any side effects.
Complex implementation as multiple components are involved in processing, persisting email requests.
You can efficiently do this if you spawn a thread for every email you have to send.
One way to do it is as follows:
You would need a class that is just a pure extension of Thread:
public class MailSenderThread extends Thread {
#Override
public void run() {
try {
// Code to send email
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
And when you want to send email, you can do:
new MailSenderThread().start();
That is the shortest/easiest way I could think of.
You can refer to an example in my public repository as well. It's off-topic but it gets the concept.
What I am doing:
I am using play 2.5.7 (java) and trying to build a REST application.
When I get a call on my controller I ask the first actor, this actor can only solve part of the problem (getting additional data), which needs to be forwarded to another actor which uses the request data and additional data to update some more data, send an async void call (tell) to another actor and respond to the controller. All these (4) actors are #Injected in other actors or controller with Guice.
Flow of calls:
controller --(Patterns.ask)--> actor1 --(actor.forward)--> actor2 --(actor.forward)--> actor3 (-tell-> actor4) and --(sender().tell)--> controller.
Issue:
This works for first 4 calls. Then on actor1.forward keeps failing on every consecutive request; Patterns.ask times out. System.out on the line before actor1.forward works but not the actual forward. No matter the timeout value (tried even 20s). No change done in the request; I just hit the send button in postman every time.
I have two questions:
Why 4? Why does it fail after 4th request? Is it some config? What should I look for in config?
Is what I am doing with actors correct way to build a REST web service?
Update: I found the issue; it was caused due to consumption of Redis connections through the pool and never freeing them. But the second question I had still remains, is what I am doing here advisable?
Sure, this could be a reasonable design. But I would consider though whether it would be more maintainable to work with Future returning methods, unless your workflow requires some complex protocol between multiple moving pieces or internal state. It may also be worth considering Akka Streams, if your processing doesn't map well to async method calls.
Basically, actors are a pretty low-level tool. To the extent that you need them, I would try to minimize the surface area of your application where they are being directly used. Higher-level abstractions are better, where possible.