It's been around 2 years, since I am developing a RESTful API using Spring Boot. The project has already been released.
This is my first project as a developer and from the beginning, I am working by myself for the server side of this project. Before this project, I didn't have any experience with production level project. The API is working fine.
Now I have added few multi-tasks in the API. Beside the main task (thread), there are the below mentioned tasks (threads running parallel):
- one tasks (thread) that checks database if there is an active targeted campaign and if there is an one, then it will check the database for targeted user for this targeted campaign. If there isn't a active campaign, then no user search will taken place but this thread will continue to look if a new targeted campaign has been placed all the time with a period of 5 seconds. For each targeted campaign a new thread will be started (I am assuming that this will cause the most consumption of CPU)
- another task check some user's location every 5 seconds
These all threads are independent to each other.
time period for both tasks could be changed.
The main issue I am facing here is that after running these tasks with main thread, almost the whole CPU is being consumed (~95%) without having any activeness from user. I stopped the parallel threads to see how the situation is being changed and it turns out that then only 9-10% CPU is being consumed for the main threads. This indicates that the parallel tasks (threads) consuming around 70-80% CPU (I am assuming because they're continuously checking database and user location.) On the other hand, the main threads being active only user is being active.
I am trying myself to decrease the CPU consumption considering that all the treads are running but still could not solve it. I tried searching through online and here in Stackeoverflow, specially this question is closed one, unfortunately using this helps, I could not solve my issue. I am not sure, but thinking, whether I should increase the resource in server (like processor core)?
That's why I am looking for some helps, suggestions, advice or guidance, which could help me to fix this issue. Or at least some tips or hints how I should proceed to solve this.
In the project I am using PostgreSQL database.
If the formation of this question is not so understandable, kindly comment about it, I will try my best to explain.
Code to send a targeted gift (campaign):
public void sendSuperTargetedGift(Gift gift){
SuperTargetedGiftCourier superTargetedGiftCourier = new SuperTargetedGiftCourier(userRepository, giftService, userLocationRepository,
locationRepository, userGiftService, giftRepository, notificationsRepository, userAgeTester, imageRepository);
superTargetedGiftCourier.setGift(gift);
taskExecutor.execute(superTargetedGiftCourier);
}
the run method:
@Override
public void run() {
try {
Location location = locationRepository.getLocationByGiftIDForGiftWhoHasOnlyOneLocation(gift);
int count = location.getGiftCount();
int giftID = gift.getGiftID();
int taken;
while (giftAvailable(gift)) {
Set<Integer> targetedUser = giftService.targetedUsers(gift);
List<User> users = getOrderedUsersByLastLocationUpdate();
if(users.size() > 0){
for (User user : users) {
try {
if(giftAvailable(gift)){
int userID = user.getUserID();
if (!userGiftService.IsUserHaveThisGift(giftID, userID) && ageCheck(gift, userID)
&& !notificationsRepository.getByNotificationByUserIdAndGiftIdForSuperTargetedGift(userID, gift.getGiftID()).isPresent())
{
//make sure user has location in database
if(userLocationRepository.getByUserUserID(userID).isPresent()){
UserLocation userLocation = userLocationRepository.getByUserUserID(userID).get();
double latitude = userLocation.getUserLatitude();
double longitude = userLocation.getUserLongitude();
if (giftService.userUnderSuperTargetedCriteria(userID, gift, latitude, longitude, targetedUser)){
giftService.setSuperTargetedNotification(userID, gift);
Location n_location = locationRepository.getLocationByGiftIDForGiftWhoHasOnlyOneLocation(gift);
taken = n_location.getGiftCollected();
if(count == taken || new Date().after(gift.getGiftDateMapEnd())){
break;
}
}
}
}//end of outer if block
}
else {
return;
}
}
catch (Exception e){
System.out.println("Exception super target gift sending: " + e);
}
}//end for loop
}
}
}
catch (Exception e) {
System.out.println("Super targeted gift sending exception: " + e);
}
}
Some notes regarding the target campaign and location check:
- As it mentioned that target campaign will only be run if there is an existing one, otherwise it will not run but check database if a new target campaign has appeared. And till now there wasn't any target campaign. So until now server CPU consumption is being used just to check database for a target campaign.
- similar for location check. it will be taken place only if there is the condition for it. And for this also, still the necessary condition has not met in database to check a user location. So location check thread is checking if the condition has appeared in database.
Probably it would also be helpful to me if I could have some guidelines regarding things I should be aware of to have a healthy server load, like required server resources for multi-threading API.