Is HealthIndicator thread safe? - spring-boot

Do I have to make the method check() thread-safe?
#Component
public class MyHealthIndicator implements HealthIndicator {
#Autowired
private MyComponent myComponent;
#Override
public Health health() {
int errorCode = myComponent.check();
if (errorCode != 0) {
return Health.down().withDetail("Error Code", errorCode).build();
}
return Health.up().build();
}
}
Is the request to the corresponding actuator endpoint executed in a separated thread?
The app logic itself has only one thread.

To answer the direct question you asked ...
Do I have to make the method check() thread-safe?
You don't have to make it thread-safe, but if your application requires that myComponent.check() is only executed by a single thread at once, then yes, you'll need to mark it synchronized.
To answer the more general question
Is HealthIndicator thread safe?
By default, each health check initiated (often by an HTTP call, perhaps to /actuator/health) will run on a single thread, and check the health of each component that's registered a HealthIndicator sequentially, and thus the individual request is single-threaded.
HOWEVER ... there's nothing to stop multiple clients each making a request to /actuator/health at the same time, and thus there may be multiple health checks in progress at the same time, each of which will be executing on a different thread.
Therefore, if there's some reason why myComponent.check() should not be executed by more than one thread concurrently, you will need to mark it synchronized or else add in some other concurrency limiting mechanisms (e.g. java.util.concurrent.Semaphore).

Related

Spring-Boot: scalability of a component

I am trying Spring Boot and think about scalabilty.
Lets say I have a component that does a job (e.g. checking for new mails).
It is done by a scheduled method.
e.g.
#Component
public class MailMan
{
#Scheduled (fixedRateString = "5000")
private void run () throws Exception
{ //... }
}
Now the application gets a new customer. So the job has to be done twice.
How can I scale this component to exist or run twice?
Interesting question but why Multiple components per customer? Can scheduler not pull the data for every customer on scheduled run and process the record for each customer? You component scaling should not be decided based on the entities evolved in your application but the resources utilization by the component. You can have dedicated components type for processing the messages for queues and same for REST. Scale them based on how much each of them is getting utilized.
Instead of using annotations to schedule a task, you could do the same thing programmatically by using a ScheduledTaskRegistrar. You can register the same bean multiple time, even if it is a singleton.
public class SomeSchedulingConfigurer implements SchedulingConfigurer {
private final SomeJob someJob; <-- a bean that is Runnable
public SomeSchedulingConfigurer(SomeJob someJob) {
this.someJob = someJob;
}
#Override
public void configureTasks(#NonNull ScheduledTaskRegistrar taskRegistrar) {
int concurrency = 2;
IntStream.range(0, concurrency)).forEach(
__ -> taskRegistrar.addFixedDelayTask(someJob, 5000));
}
}
Make sure the thread executor you are using is large enough to process the amount of jobs concurrently. The default executor has exactly one thead :-). Be aware that this approach has scaling limits.
I also recommend to add a delay or skew between jobs, so that not all jobs run at exactly the same moment.
See SchedulingConfigurer
and
ScheduledTaskRegistrar
for reference.
The job needs to run only once even with multiple customers. The component itself doesn't need to scale at all. It just a mechanism to "signal" that some logic needs to be run at some moment in time. I would keep the component really thin and just call the desired business logic that handles all the rest e.g.
#Component
public class MailMan {
#Autowired
private NewMailCollector newMailCollector;
#Scheduled (fixedRateString = "5000")
private void run () throws Exception {
// Collects emails for customers
newMailCollector.collect();
}
}
If you want to check for new e-mails per customer you might want to avoid using scheduled tasks in a backend service as it will make the implementation very inflexible.
Better make an endpoint available for clients to call to trigger that logic.

How to propagate JTA state when using reactive-messaging?

I would like to propagate JTA state (= the transaction) between a transactional REST endpoint that emits a message to a reactive-messaging connector.
#Inject
#Channel("test")
Emitter<String> emitter;
#POST
#Transactional
public Response test() {
emitter.send("test");
}
and
#ApplicationScoped
#Connector("test")
public class TestConnector implements OutgoingConnectorFactory {
#Inject
TransactionManager tm;
#Override
public SubscriberBuilder<? extends Message<?>, Void> getSubscriberBuilder(Config config) {
return ReactiveStreams.<Message<?>>builder()
.flatMapCompletionStage(message -> {
tm.getTransaction(); // = null
return message.ack();
})
.ignore();
}
}
As I understand, context-propagation is responsible for making the transaction available (see io.smallrye.context.jta.context.propagation.JtaContextProvider#currentContext). The problem seems to be, that currentContext gets created on subscription, which happens when the injection point (Emitter<String> emitter) get its instance. Which is too early to properly capture the transaction.
What am I missing?
By the way, I am having the same problem when using #Incoming / #Outgoing instead of the emitter. I have decided to give you this example because it is easy to understand and reproduce.
At the moment, you need to pass the current Transaction in the message metadata. Thus, it will be propagated to your different downstream components (as well as the connector).
Note that, Transaction tends to be attached to the request scope, which means that in your connector, it may already be too late to use it. So, make sure your endpoint is asynchronous and only returns when the emitted message is acknowledged.
Context Propagation is not going to help in this case as the underlying streams are built at startup time (at build time in Quarkus) so, there are no capture contexts.

Should I implement synchronization in multi-listener scenarios?

I have a class which has two different listener methods. One is for listening to different messages and another one is for listening to state updates.
#Override
public void receive(Message message) {
if (message.getObject() instanceof Boolean) {
membership.put(message.src(), message.getObject());
log.info("Membership state updated: {}", membership);
}
}
#Override
public void setState(InputStream input) throws Exception {
System.out.println("setState() works");
Map<Address, Boolean> state = Util.objectFromStream(new DataInputStream(input));
synchronized (membership) {
//membership.clear();
membership.putAll(state);
}
log.info("Set new membership state: {}", membership);
}
I haven't added enough context because they are unnecessary for this question. Here membership is a HashMap which gets updated by both listener methods. receive() is heavily used however is less critical. But setState() is rarely used but highly critical.
My question is: should I use synchronization for both methods. In case if setState() is called by a thread (say A) while receive() is still in execution by another thread (say B), should I worry about race condition in this case.
I really don't want to add synchronized to receive because this would impact performance.
Any insight is really helpful. Thanks in advance.
If those methods, and any other that access the membership can be called by different threads concurrently you will face race conditions. And you need to take into account not only methods that update the map, but also the ones reading it.
You can avoid using synchronized in all methods that write or read from the map, by using a ConcurrentHashMap, a highly optimized thread-safe version of HashMap.

Why is it beneficial to make async REST services?

Spring allows a method annotated with #RequestMapping to return a variety of objects, including a CompletableFuture or a Future. This allows me to spawn off an async method and let spring return the value whenever it is ready. What I am not sure I am understanding is if there are any benefits to this. For instance:
#RestController
public class MyController {
#RequestMapping("/user/{userId}")
public CompletableFuture<User> getUser(#PathVariable("userId") String userId) {
return CompletableFuture.supplyAsync(
() -> this.dataAccess.getUser(userId));
}
In this case, even though the actual computation is happening in the background, the connection will still not close and the request thread will still be active till it is done. How is it better than say:
#RequestMapping("/user/{userId}")
public User getUser(#PathVariableS("userId") String userId) {
return this.dataAccess.getUser(userId);
}
From first glances, this seems to be a better approach as there is no overhead with an additional thread and a watcher that looks for completion.
This takes advantage of Servlet 3 asynchronous request processing, using request.startAsync() method. Read here and here
To achieve this, a Servlet 3 web application can call request.startAsync() and use the returned AsyncContext to continue to write to the response from some other separate thread. At the same time from a client's perspective the request still looks like any other HTTP request-response interaction. It just takes longer to complete. The following is the sequence of events:

Web API concurrency and scalability

We are faced with the task to convert a REST service based on custom code to Web API. The service has a substantial amount of requests and operates on data that could take some time to load, but once loaded it can be cached and used to serve all of the incoming requests. The previous version of the service would have one thread responsible for loading the data and getting it into the cache. To prevent the IIS from running out of worker threads clients would get a "come back later" response until the cache was ready.
My understanding of Web API is that it has an asynchronous behavior built in by operating on tasks, and as a result the number of requests will not directly relate to the number of physical threads being held.
In the new implementation of the service I am planning to let the requests wait until the cache is ready and then make a valid reply. I have made a very rough sketch of the code to illustrate:
public class ContactsController : ApiController
{
private readonly IContactRepository _contactRepository;
public ContactsController(IContactRepository contactRepository)
{
if (contactRepository == null)
throw new ArgumentNullException("contactRepository");
_contactRepository = contactRepository;
}
public IEnumerable<Contact> Get()
{
return _contactRepository.Get();
}
}
public class ContactRepository : IContactRepository
{
private readonly Lazy<IEnumerable<Contact>> _contactsLazy;
public ContactRepository()
{
_contactsLazy = new Lazy<IEnumerable<Contact>>(LoadFromDatabase,
LazyThreadSafetyMode.ExecutionAndPublication);
}
public IEnumerable<Contact> Get()
{
return _contactsLazy.Value;
}
private IEnumerable<Contact> LoadFromDatabase()
{
// This method could be take a long time to execute.
throw new NotImplementedException();
}
}
Please do not put too much value in the design of the code - it is only constructed to illustrate the problem and is not how we did it in the actual solution. IContactRepository is registered in the IoC container as a singleton and is injected into the controller. The Lazy with LazyThreadSafetyMode.ExecutionAndPublication ensures only the first thread/request is running the initialization code, the following rquests are blocked until the initialization completes.
Would Web API be able to handle 1000 requests waiting for the initialization to complete while other requests not hitting this Lazy are being service and without the IIS running out of worker threads?
Returning Task<T> from the action will allow the code to run on the background thread (ThreadPool) and release the IIS thread. So in this case, I would change
public IEnumerable<Contact> Get()
to
public Task<IEnumerable<Contact>> Get()
Remember to return a started task otherwise the thread will just sit and do nothing.
Lazy implementation while can be useful, has got little to do with the behaviour of the Web API. So I am not gonna comment on that. With or without lazy, task based return type is the way to go for long running operations.
I have got two blog posts on this which are probably useful to you: here and here.

Resources