Krishna
Krishna

Reputation: 761

Spring Boot gives different response while load test(50 users) time

We have upgraded the project technology from Java servlet to Spring Boot. It's working fine for single user transaction mode, but it's not working multiple users test.

My Project configuration

UI - angular
Business Logic- Java Spring Boot
back end - No SQL get call
No hibernate

Session - stateless session
We don't process based on the user's session. We process only employee id and case id(75 % get request, 25 % post request). it's working fine for single user time. LoadNinja load test run 50 users time - we will get another user's response to me.

My name is Apple if I am requesting for my details(load ninja run the same process for 50 user test simultaneously) to the server , but i am getting response as Orange user's details. Sometimes I am getting a Null pointer exception.

I am unable to trace the cause of the issue - Could you please advise for project configuration changes.

Thanks in advance.

EmployeeController.java

package com.apa.documentprocessor.constants;

import java.io.IOException;

import javax.xml.bind.JAXBException;

import org.apache.commons.httpclient.HttpException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;

@RequestMapping("/employee")
public class EmployeeController {

    @Autowired
    EmployeeService employeeservice;
    
    @Autowired
    Employee employee;
    
    @RequestMapping("/getDetails")
    public void getEmployeeDetails() throws HttpException, IOException, JAXBException {
        
        employee.setEmpId("100");
        employee.setEmpName("Nuno");
        employee.setDept("Research");
        employee.setLocation("India");
        
        
        EmployeePerformance emp = employeeservice.EmployeeDetails(employee);
        
        System.out.println(emp.toString());
        
        
    }
    
}

EmployeeService.java

package com.apa.documentprocessor.constants;

import java.io.IOException;
import java.io.StringReader;


import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.stereotype.Component;
import org.xml.sax.InputSource;



@Component
public class EmployeeService {

    @Autowired
    EmployeePerformance empPerformance;
    
    @Autowired
    private AutowireCapableBeanFactory beanFactory;
    
    public EmployeePerformance EmployeeDetails(Employee emp) throws HttpException, IOException, JAXBException {
            
        
        this.empPerformance = beanFactory.createBean(EmployeePerformance.class);
        this.empPerformance = getDetails(emp);
        
        
        return empPerformance;
        
    }


    private EmployeePerformance getDetails(Employee emp) throws HttpException, IOException, JAXBException {
        
        
        String result;
        String url=emp.getEmpName();
        
        
        HttpClient client = new HttpClient();
        GetMethod method = new GetMethod(url);
        method.addRequestHeader("3454362523", emp.getEmpId());
        
        client.executeMethod(method);
        
        result = method.getResponseBodyAsString();
        
        JAXBContext jaxbContext = JAXBContext.newInstance(EmployeePerformance.class);
        
        Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
        
        EmployeePerformance empPerformance = (EmployeePerformance) jaxbUnmarshaller
                .unmarshal(new InputSource(new StringReader(result)));
        
        
        empPerformance.setProject("Banking");
        empPerformance.setRating("Good");
        
        return empPerformance;
    }
    
    
}

EmployeePerformance.java

package com.apa.documentprocessor.constants;

import org.springframework.stereotype.Component;

@Component
public class EmployeePerformance {

    String empName;
    String rating;
    String project;
    String position;
    
    
    public String getEmpName() {
        return empName;
    }
    public void setEmpName(String empName) {
        this.empName = empName;
    }
    public String getRating() {
        return rating;
    }
    public void setRating(String rating) {
        this.rating = rating;
    }
    public String getProject() {
        return project;
    }
    public void setProject(String project) {
        this.project = project;
    }
    public String getPosition() {
        return position;
    }
    public void setPosition(String position) {
        this.position = position;
    }
    
    
}

Employee.java

package com.apa.documentprocessor.constants;

import org.springframework.stereotype.Component;

@Component
public class Employee {

    
    String empId;
    String empName;
    String dept;
    String location;
    
    
    public String getEmpId() {
        return empId;
    }
    public void setEmpId(String empId) {
        this.empId = empId;
    }
    public String getEmpName() {
        return empName;
    }
    public void setEmpName(String empName) {
        this.empName = empName;
    }
    public String getDept() {
        return dept;
    }
    public void setDept(String dept) {
        this.dept = dept;
    }
    public String getLocation() {
        return location;
    }
    public void setLocation(String location) {
        this.location = location;
    }
    
    
    
}

Upvotes: 0

Views: 544

Answers (1)

M. Deinum
M. Deinum

Reputation: 124632

Your code is flawed, don't make Employee nor EmployeePerformance spring managed beans. Just construct a new instance when you need one. The fact that one uses Spring doesn't mean everything needs to be managed by Spring.

@RequestMapping("/employee")
public class EmployeeController {

    @Autowired
    EmployeeService employeeservice;
    
    @RequestMapping("/getDetails")
    public void getEmployeeDetails() throws HttpException, IOException, JAXBException {
        Employee employee = new Employee();
        employee.setEmpId("100");
        employee.setEmpName("Nuno");
        employee.setDept("Research");
        employee.setLocation("India");
        
        EmployeePerformance emp = employeeservice.EmployeeDetails(employee);
        
        System.out.println(emp.toString());
    }  
}

Regarding the use of HttpClient don't construct one each time, instead reuse it, or even better use RestTemplate which does all of that out-of-the-box, including the marshalling.

@Component
public class EmployeeService {

    private final RestTemplate http;
    
    public EmployeeService(RestTemplate http) {
      this.http=http;
    }

    public EmployeePerformance EmployeeDetails(Employee emp) throws HttpException, IOException, JAXBException {           
        return getDetails(emp);
    }

    private EmployeePerformance getDetails(Employee emp) throws HttpException, IOException, JAXBException {
        
        String url=emp.getEmpName();
        RequestEntity req = RequestEntity.get(url).header("3454362523", emp.getEmpId()).build();  
        
        EmployeePerformance empPerformance = http.exchange(req, EmployeePerformance.class).getBody();       
        
        empPerformance.setProject("Banking");
        empPerformance.setRating("Good");
        
        return empPerformance;
    }
}

In your configuration you need to add the following

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
  return builder.requestFactory(HttpComponentsClientHttpRequestFactory.class).build();
}

With this you are not sharing state anymore and reusing heavy objects instaed of constructing them each time you need them.

Upvotes: 2

Related Questions