Logging requests and responses in Spring - spring

I'm trying to implement logging system in a Spring boot application. There are requests coming into the system which have one or more responses.
Requests and responses must be logged into the database in a separate thread, not in the worker thread.
This is my idea.
tables in mysql - "request" with required columns, and "response" with request_id as foreign key
relation between resquest and response - one to many.
A separate thread in LogService is started in #PostContruct to save the data in the DB.
I'm sure there are better solutions to this problem. Please guide with some suggestions.
#Service
public class LogServiceImpl implements LogService {
private final BlockingQueue<Object> logQueue = new LinkedBlockingQueue<>();
private volatile boolean done;
// repositories
#Autowired
private RequestRepository requestRepository;
#Autowired
private ResponseRepository responseRepository;
#Async
#Override
public void log(Object obj) {
try {
logQueue.put(obj);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
#PostContruct
private saveToDb(){
new Thread(() -> {
while(!done){
String object = logQueue.poll(5, TimeUnit.SECONDS)
if(object != null){
if(object instanceof Request){
requestRepository.save((Request)object);
}
if(object instanceof Response){
responseRepository.save((Response)object);
}
}
}
}).start();
}
public void stop() {
done = true;
}
}
class Request{
.....
}
class Response{
......
}
#Service
public class SomeService1 {
#Autowired
private LogService logService;
public void someMeth1(Request request) {
....
logService.log(request);
}
}
#Service
public class SomeService2 {
#Autowired
private LogService logService;
public void someMeth2(Response response) {
....
logService.log(response);
}
}

Related

#Transactional timeout is not working in spring boot application

I am using Spring Boot and JdbcTemplate in my application. I am trying to implement timeout for select query but its not working.
My query takes more time than timeout time but still its not giving timeout exception.
#Service
#Slf4j
public class SchedulerService
{
#Autowired
UserService userExportService;
#Autowired
private userExportDao userExportDao;
#Value("${queryTest}")
private String queryFetchByExportFlagCustom;
#Scheduled(fixedDelay=10000)
public void triggerUserExport() {
List<UserExportCustom> userList;
try {
userList = userExportDao.findByExportFlag(0, queryFetchByExportFlagCustom);
userExportService.exportUsers(userList, schedulerCount);
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Repository
#Slf4j
public class UserExportDao extends JdbcDaoImpl<UserExportCustom, Long>
{
#Autowired
BeanPropertyRowMapper<UserExportCustom> userExportCustomRowMapper;
#Transactional(readOnly = true, timeout = 1)
public List<UserExportCustom> findByExportFlag(Integer exportFlag, String query)
{
List<UserExportCustom> userExportCustomList = null;
try
{
SqlParameterSource namedParameters = new MapSqlParameterSource().addValue("exportFlag", exportFlag, Types.INTEGER);
userExportCustomList = namedParameterJdbcTemplate.query(query, namedParameters,userExportCustomRowMapper);
}
catch (Exception e)
{
e.printStackTrace();
log.error("Error in findByExportFlag: \n" + e);
}
return userExportCustomList;
}
}
public class JdbcDaoImpl<T, ID> implements JdbcDao<T, ID> {
#Autowired
protected JdbcTemplate jdbcTemplate;
#Autowired
protected NamedParameterJdbcTemplate namedParameterJdbcTemplate;
#Override
public List<T> findAll() {
throw new IllegalStateException();
}
#Override
public T save(T api) {
throw new IllegalStateException();
}
#Override
public T update(T api) {
throw new IllegalStateException();
}
#Override
public T saveOrUpdate(T api) {
throw new IllegalStateException();
}
#Override
public T findOne(String unique) {
throw new IllegalStateException();
}
#Override
public T findOneById(ID id) {
throw new IllegalStateException();
}
#Override
public void delete(ID id) {
throw new IllegalStateException();
}
}
If query take more than 1 second than it should give timeout exception but it does not.
try{}catch{} will lead #Transactional to fail ,remove try catch

Spring `#Autowire` field is `null` eventhough it works fine in other classes

Spring #Autowire field is null even though it works fine in other classes successfully.
public class SendRunner implements Runnable {
private String senderAddress;
#Autowired
private SubscriberService subscriberService;
public SendRunner(String senderAddress) {
this.senderAddress = senderAddress;
}
#Override
public void run() {
sendRequest();
}
private void sendRequest() {
try {
HashMap<String, String> dataMap = new HashMap<>();
dataMap.put("subscriberId", senderAddress);
HttpEntity<?> entity = new HttpEntity<Object>(dataMap, httpHeaders);
Subscriber subscriber = subscriberService.getSubscriberByMsisdn(senderAddress);
} catch (Exception e) {
logger.error("Error occurred while trying to send api request", e);
}
}
Also this class is managed as a bean in the dispatcher servlet :
<bean id="SendRunner" class="sms.dating.messenger.connector.SendRunner">
</bean>
In here i'm getting a null pointer exception for subscriberService. What would be the possible reason for this? Thanks in advance.
Can you please try with below code snippet
#Configuration
public class Someclass{
#Autowired
private SubscriberService subscriberService;
Thread subscriberThread = new Thread() {
#Override
public void run() {
try {
HashMap<String, String> dataMap = new HashMap<>();
dataMap.put("subscriberId", senderAddress);
HttpEntity<?> entity = new HttpEntity<Object>(dataMap, httpHeaders);
Subscriber subscriber = subscriberService.getSubscriberByMsisdn(senderAddress);
} catch (Exception e) {
logger.error("Error occurred while trying to send api request", e);
}
}
};
}
Can you please annotate your SendRunner class with #Component or #Service and include the SendRunner package in componentscanpackage
Your bean not in Spring Managed context, below can be the reasons.
Package sms.dating.messenger.connector not in Component scan.
You are moving out of the Spring context by creating an object with new (see below),
this way you will not get the autowired fields.
SendRunner sendRunner = new SendRunner () ,
sendRunner.sendRequest();
Just check how I implement. Hope this will help.
#RestController
public class RestRequest {
#Autowired
SendRunner sendRunner;
#RequestMapping("/api")
public void Uri() {
sendRunner.start();
}
}
SendRunner class
#Service
public class SendRunner extends Thread{
#Autowired
private SubscriberService subscriberService;
#Override
public void run() {
SendRequest();
}
private void SendRequest() {
System.out.println("Object is " + subscriberService);
String senderAddress = "address";
subscriberService.getSubscriberByMsisdn(senderAddress);
}
}
Below are the logs printed when I hit the REST api.
Object is com.example.demo.SubscriberService#40f33492

Spring Boot Isolation.SERIALIZABLE not working

I need help with this scenario, in theory the isolation level of Serializable should stop delete from happening, but in this scenario it still deletes the row with id 1, I have tried #EnableTransactionManagement and isolation repeatable read, it still doesn't block the delete nor cause the delete to throw exception
In summary, I need to stop any delete invocation whenever the update method is still ongoing
I am using H2 in memory database for this sample
Thanks
Entity:
public class Something {
#Id
private Integer id;
private String name;
private String desc;
}
Repo:
public interface SomeRepository extends JpaRepository<Something, Integer> {
}
Service:
#Service
public class SomeService {
#Autowired
private SomeRepository someRepository;
public void deleteSomething2(Something something) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
someRepository.delete(something);
}
#Transactional(isolation = Isolation.SERIALIZABLE)
public void updateSomething2(Something something) {
Something something1 = someRepository.findById(1).get();
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
something1.setName("namanama");
someRepository.saveAndFlush(something1);
}
Test:
#RunWith(SpringRunner.class)
#SpringBootTest
public class DemoApplicationTests {
#Autowired
private SomeService service;
#Test
public void test() throws Exception {
ExecutorService executorService = Executors.newFixedThreadPool(10);
List<Future> futures = new ArrayList<>();
futures.add(executorService.submit(() -> service.updateSomething2(Something.builder().id(1).name("namaone").build())));
futures.add(executorService.submit(() -> service.deleteSomething2(Something.builder().id(1).build())));
while(futures.stream().filter(f -> f.isDone() == false).count() > 0) {
Thread.sleep(3000);
}
List<Something> all = service.findAll();
System.out.println(all);
}
}

Best way to limit time execution in a #RestController

Considering the following code:
#RestController
#RequestMapping("/timeout")
public class TestController {
#Autowired
private TestService service;
#GetMapping("/max10secs")
public String max10secs() {
//In some cases it can take more than 10 seconds
return service.call();
}
}
#Service
public class TestService {
public String call() {
//some business logic here
return response;
}
}
What I want to accomplish is that if the method call from the TestService takes more than 10 seconds I want to cancel it and generate a response with a HttpStatus.REQUEST_TIMEOUT code.
What I managed to do, but I don't know if there are any conceptual or practical flaws is what it follows...
First, the configuration of spring-async
#Configuration
#EnableAsync
public class AsyncConfig implements AsyncConfigurer {
#Bean(name = "threadPoolTaskExecutor")
public Executor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor();
pool.setCorePoolSize(10);
pool.setMaxPoolSize(10);
pool.setWaitForTasksToCompleteOnShutdown(true);
return pool;
}
#Override
public Executor getAsyncExecutor() {
return new SimpleAsyncTaskExecutor();
}
}
And next, the Controller and Service modifications:
#RestController
#RequestMapping("/timeout")
public class TestController {
#Autowired
private TestService service;
#GetMapping("/max10secs")
public String max10secs() throws InterruptedException, ExecutionException {
Future<String> futureResponse = service.call();
try {
//gives 10 seconds to finish the methods execution
return futureResponse.get(10, TimeUnit.SECONDS);
} catch (TimeoutException te) {
//in case it takes longer we cancel the request and check if the method is not done
if (futureResponse.cancel(true) || !futureResponse.isDone())
throw new TestTimeoutException();
else {
return futureResponse.get();
}
}
}
}
#Service
public class TestService {
#Async("threadPoolTaskExecutor")
public Future<String> call() {
try{
//some business logic here
return new AsyncResult<>(response);
} catch (Exception e) {
//some cancel/rollback logic when the request is cancelled
return null;
}
}
}
And finally generate the TestTimeoutException:
#ResponseStatus(value = HttpStatus.REQUEST_TIMEOUT, reason = "too much time")
public class TestTimeoutException extends RuntimeException{ }
There is another solution via DeferredResult.
TestController.java
#RestController
#RequestMapping("/timeout")
public class TestController
{
#Autowired
private TestService service;
#GetMapping("/max10secs")
public DeferredResult<String> max10secs()
{
//In some cases it can take more than 10 seconds
return service.call();
}
}
TestService.java
#Service
public class TestService
{
public DeferredResult<String> call()
{
DeferredResult<String> result = new DeferredResult(10000L);
//some business logic here
result.onTimeout(()->{
// do whatever you want there
});
result.setResult("test");
return result;
}
}
This way, controller will return actual result only when you call result.setResult("test");.
As you can see, in case of timeout (value for timeout is defined in constructor of DeferredResult object in milliseconds) there will be a callback executed where you can throw any exception, or return another object(HttpStatus.REQUEST_TIMEOUT in your case).
You can read about the DeferredResult in Spring here.

How do I write a unit test to verify async behavior using Spring 4 and annotations?

How do I write a unit test to verify async behavior using Spring 4 and annotations?
Since i'm used to Spring's (old) xml style), it took me some time to figure this out. So I thought I answer my own question to help others.
First the service that exposes an async download method:
#Service
public class DownloadService {
// note: placing this async method in its own dedicated bean was necessary
// to circumvent inner bean calls
#Async
public Future<String> startDownloading(final URL url) throws IOException {
return new AsyncResult<String>(getContentAsString(url));
}
private String getContentAsString(URL url) throws IOException {
try {
Thread.sleep(1000); // To demonstrate the effect of async
InputStream input = url.openStream();
return IOUtils.toString(input, StandardCharsets.UTF_8);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
}
Next the test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class DownloadServiceTest {
#Configuration
#EnableAsync
static class Config {
#Bean
public DownloadService downloadService() {
return new DownloadService();
}
}
#Autowired
private DownloadService service;
#Test
public void testIndex() throws Exception {
final URL url = new URL("http://spring.io/blog/2013/01/16/next-stop-spring-framework-4-0");
Future<String> content = service.startDownloading(url);
assertThat(false, equalTo(content.isDone()));
final String str = content.get();
assertThat(true, equalTo(content.isDone()));
assertThat(str, JUnitMatchers.containsString("<html"));
}
}
If you are using the same example in Java 8 you could also use the CompletableFuture class as follows:
#Service
public class DownloadService {
#Async
public CompletableFuture<String> startDownloading(final URL url) throws IOException {
CompletableFuture<Boolean> future = new CompletableFuture<>();
Executors.newCachedThreadPool().submit(() -> {
getContentAsString(url);
future.complete(true);
return null;
});
return future;
}
private String getContentAsString(URL url) throws IOException {
try {
Thread.sleep(1000); // To demonstrate the effect of async
InputStream input = url.openStream();
return IOUtils.toString(input, StandardCharsets.UTF_8);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
}
Now the test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class DownloadServiceTest {
#Configuration
#EnableAsync
static class Config {
#Bean
public DownloadService downloadService() {
return new DownloadService();
}
}
#Autowired
private DownloadService service;
#Test
public void testIndex() throws Exception {
final URL url = new URL("http://spring.io/blog/2013/01/16/next-stop-spring-framework-4-0");
CompletableFuture<Boolean> content = service.startDownloading(url);
content.thenRun(() -> {
assertThat(true, equalTo(content.isDone()));
assertThat(str, JUnitMatchers.containsString("<html"));
});
// wait for completion
content.get(10, TimeUnit.SECONDS);
}
}
Please that when the time-out is not specified, and anything goes wrong the test will go on "forever" until the CI or you shut it down.

Resources