Deferred calculations in Spring MVC - java

Suppose I have some service S that receives requests from client C.
S cannot response immediately due to heavy calculations, C also cannot wait until forever and has his own timeout period.
My idea is to implement the server side as described here:
REST and long running jobs, Farazdagi
In my ServerController I have a thread pool for deferred calculations and a concurrent map to store responses.
private final int NUMBER_OF_WORKERS = 10;
private Map<String, ResponseEntity<MathResponse>> responseMap = new ConcurrentHashMap<>();
private ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_OF_WORKERS);
My /calculate mapping submits jobs to the thread pool and returns with 202 (Accepted) HTTP status and puts redirection link to Location header.
#RequestMapping(value = "/calculate", method = RequestMethod.POST)
public ResponseEntity<String> startWorkflow(#RequestBody MathRequest request, UriComponentsBuilder builder) {
UUID uuid = UUID.randomUUID();
executorService.submit(() -> {
// time-consuming calculations here
ResponseEntity<MathResponse>response = HardMath.execute(request)
responseMap.put(uuid.toString(), response);
});
HttpHeaders headers = new HttpHeaders();
UriComponents uriComponents = builder.path("/wf/queue/{id}").buildAndExpand(uuid.toString());
headers.setLocation(uriComponents.toUri());
return new ResponseEntity<>(headers, HttpStatus.ACCEPTED);
}
In /queue/id mapping I return result if it's in the map:
#RequestMapping(value = "/queue/{id}", method = RequestMethod.GET)
public ResponseEntity<MathResponse> getQueueInfo(#PathVariable("id") String id) {
ResponseEntity<MathResponse> defaultQueueResponse = new ResponseEntity<>(new MathResponse(), HttpStatus.OK);
return responseMap.getOrDefault(id, defaultQueueResponse);
}
I suppose that using such low-level things like ConcurrentHashMap is not a good idea. Are there any options in Spring that I could use instead of reinventing the wheel?

There's also the question of resilience; if the results are local to an instance of S (i.e. in an in-process Map) then if that instance of S crashes or is restarted then the results are lost and C would be forced to resubmit its request(s). If the results cache within S was backed by a resilient store then the results could survive a crash/restart of S.
Spring's caching abstraction with a backing store of <insert storage technology here> could help.

Related

Test of endpoint that sends a request to external api

There is a small method mymethod that gets the response from the external api data in json format, which will be Dto and
then there is a getEnums method that selects which data to leave and returns a list of strings and as a result mymethod itself returns a list of strings.
I tried to write a test, but I get :
Expected :200
Actual :302
As I understand the problem is in the redirection, but how to solve it I do not understand, maybe you have an answer?
controller
#GetMapping(value = "api/mymethod", produces = "application/json")
public ResponseEntity<List<String>> mymethod(#RequestHeader(value = "Enum") String Enum,
#RequestParam(value = "Type") String Type) {
URI uri = UriComponentsBuilder.fromUriString("...url...").build().toUri();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(null, headers);
ResponseEntity<myDto> response =
restTemplate.exchange(uri, HttpMethod.GET, entity, myDto.class);
List<String> currencies =
getEnums(response, Type); // <- custom method
return new ResponseEntity<>(currencies, HttpStatus.OK);
}
// (The test is not written in full, left exactly the problem area)
test
#Test
public void mytest() throws Exception{
ResultActions getResult = mockMvc.perform(get("/api/mymethod")
.header("Enum", "OOL")
.param("Type", "Counter"))
.andExpect(status().isOk());
}
The problem with testing against an external service is that you do not manage it's state. Therefore your test cases may show varying results even if you did not change anything.
Usually you'd create a mock of the REST api your test object would access. Then you can send requests to your test object and check in the mocked api whether the expected requests did come in. You can also fake success or error responses and check how your test object reacts.
To finally answer your question: How do you want your client to treat a redirection? Should it follow or error out? Looking at the meaning of status 302 it means the resource has moved temporarily or at least was found at a new location. This might mean a valid redirect if the server is trying to loadbalance or tries to point out a url that is closer to you network-wise. Therefore I believe the client should follow a 302.

Async Java method for Azure Function App?

I am currently working on creating the EventhubTriggered Java function app which listenes to the default-endpoint of the IotHub. Currently following the tutorials, I donot see any sample codes for Async implementation for Java Function Apps while it is recommended to use async/await for C# function apps.
Should I consider/ is it possible to add Async implementation for Function Apps in Java? Is there any sample code I can take a reference from? Should I consider adding parallel programming/Multithreading logic in the function app?
https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-event-hubs-trigger?tabs=java#example
https://learn.microsoft.com/en-us/java/api/com.microsoft.azure.functions.annotation.eventhubtrigger?view=azure-java-stable
Java does not have async/await but it has reactive/webflux.
When you create default project azure function it should be packaged with reactive so you just need to make your calls in reactive way.
So lets say if you want to do some call to external sources your code will look like
public Mono<ResponseEntity<WishlistDto>> getList(String profileId, String listId) {
return service.getWishList(profileId, listId)
.map(w -> ResponseEntity.ok().body(DtoMapper.convertToDto(w, true)))
.defaultIfEmpty(ResponseEntity.notFound().build());
}
But I would recommend you to use input/output bindings as much as you can
#FunctionName("DocByIdFromQueryString")
public HttpResponseMessage run(
#HttpTrigger(name = "req",
methods = {HttpMethod.GET, HttpMethod.POST},
authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<Optional<String>> request,
#CosmosDBInput(name = "database",
databaseName = "ToDoList",
collectionName = "Items",
id = "{Query.id}",
partitionKey = "{Query.partitionKeyValue}",
connectionStringSetting = "Cosmos_DB_Connection_String")
Optional<String> item,
final ExecutionContext context)
In this case you dont need to worry much about reactive since your function starts as soon as every thing is ready and java sdk will take care of it
Another example to use output bindings
#FunctionName("sbtopicsend")
public HttpResponseMessage run(
#HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
#ServiceBusTopicOutput(name = "message", topicName = "mytopicname", subscriptionName = "mysubscription", connection = "ServiceBusConnection") OutputBinding<String> message,
final ExecutionContext context) {
String name = request.getBody().orElse("Azure Functions");
message.setValue(name);
return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
}
I release a new project JAsync implement async-await fashion in java which use Reactor as its low level framework. It is in the alpha stage. I need more suggest and test case.
This project makes the developer's asynchronous programming experience as close as possible to the usual synchronous programming, including both coding and debugging.
Here is an example:
#RestController
#RequestMapping("/employees")
public class MyRestController {
#Inject
private EmployeeRepository employeeRepository;
#Inject
private SalaryRepository salaryRepository;
// The standard JAsync async method must be annotated with the Async annotation, and return a JPromise object.
#Async()
private JPromise<Double> _getEmployeeTotalSalaryByDepartment(String department) {
double money = 0.0;
// A Mono object can be transformed to the JPromise object. So we get a Mono object first.
Mono<List<Employee>> empsMono = employeeRepository.findEmployeeByDepartment(department);
// Transformed the Mono object to the JPromise object.
JPromise<List<Employee>> empsPromise = Promises.from(empsMono);
// Use await just like es and c# to get the value of the JPromise without blocking the current thread.
for (Employee employee : empsPromise.await()) {
// The method findSalaryByEmployee also return a Mono object. We transform it to the JPromise just like above. And then await to get the result.
Salary salary = Promises.from(salaryRepository.findSalaryByEmployee(employee.id)).await();
money += salary.total;
}
// The async method must return a JPromise object, so we use just method to wrap the result to a JPromise.
return JAsync.just(money);
}
// This is a normal webflux method.
#GetMapping("/{department}/salary")
public Mono<Double> getEmployeeTotalSalaryByDepartment(#PathVariable String department) {
// Use unwrap method to transform the JPromise object back to the Mono object.
return _getEmployeeTotalSalaryByDepartment(department).unwrap(Mono.class);
}
}
In addition to coding, JAsync also greatly improves the debugging experience of async code.
When debugging, you can see all variables in the monitor window just like when debugging normal code.

Activiti REST API not retrieving tasks anymore

After a couple of years of normal operations, the API of Activiti 5.17.0 to retrieve tasks is not returning the latest tasks anymore.
The API invoked is a GET to /runtime/tasks?includeProcessVariables=true&size=600000&order=desc with basic authentication.
Nobody changed it, but it is just stuck at returning tasks from 10 days ago.
I checked the Activiti tables and they contain the records for the tasks I need to retrieve.
I also tried to cleanup some old data from act_hi_taskinst and act_ru_task and from , supposing it was a matter of cardinality (maybe too many tasks), but nothing changed.
I also tried to increase the size parameter in the request, but nothing changes (not reaching that limit).
What is going on?
--- Edit
It seems a matter of IDs. If I try to get the last 10 tasks order by create_time_ desc, only tasks until ID 999907 are returned. The next ID is over 1.000.000 and I can see it in the database, but the API is not returning it.
I changed the order by: ordering by id (which is a varying char in the database) is counterintuitive. In fact, when order by id_ desc the tasks with ID over 1.000.000 are AFTER tasks 900.000.
Putting the size to Integer.MAX_VALUE did not fix the problem, for some reason I don't get (maybe the reason is inside Activiti query building code).
BTW I changed the order and used createTime desc. This was, most recent tasks are returned regardless of their ID.
Here's my custom-tailored controller (to be improved, but working for my specific use case).
#RestController
#RequestMapping("/api/")
public class CustomRest extends TaskBaseResource {
#Autowired
TaskService taskService;
/*
#RequestMapping(method = RequestMethod.GET, path = "custom")
public List<Task> retrieveAllTasks() {
return taskService.createTaskQuery().includeProcessVariables().active().list();
}
*/
#RequestMapping(method = RequestMethod.GET, path = "custom")
public DataResponse getTasks(#RequestParam Map<String, String> requestParams, HttpServletRequest httpRequest) {
// Create a Task query request
TaskQueryRequest request = new TaskQueryRequest();
// Populate filter-parameters
if (requestParams.containsKey("name")) {
request.setName(requestParams.get("name"));
}
request.setIncludeProcessVariables(true);
request.setActive(true);
return getTasksFromQueryRequest(request, requestParams);
}
protected DataResponse getTasksFromQueryRequest(TaskQueryRequest request,
Map<String, String> requestParams) {
TaskQuery taskQuery = taskService.createTaskQuery();
taskQuery.active();
taskQuery.includeProcessVariables();
HashMap<String, QueryProperty> properties = new HashMap<String, QueryProperty>();
properties.put("id", TaskQueryProperty.TASK_ID);
properties.put("name", TaskQueryProperty.NAME);
properties.put("description", TaskQueryProperty.DESCRIPTION);
properties.put("dueDate", TaskQueryProperty.DUE_DATE);
properties.put("createTime", TaskQueryProperty.CREATE_TIME);
properties.put("priority", TaskQueryProperty.PRIORITY);
properties.put("executionId", TaskQueryProperty.EXECUTION_ID);
properties.put("processInstanceId", TaskQueryProperty.PROCESS_INSTANCE_ID);
properties.put("tenantId", TaskQueryProperty.TENANT_ID);
request.setSize(Integer.MAX_VALUE);
//request.setSize(10);
request.setOrder("createTime");
request.setOrder("desc");
DataResponse paginatedList = new TaskPaginateList(restResponseFactory).paginateList(
requestParams, request, taskQuery, "createTime", properties);
return paginatedList;
}
}

Undertow handlers make all stack Non-Blocking

I'm studying undertow because I've seen is a good choice if you want to implement Non-Blocking IO and you want to have a reactive http listener.
Undertow uses handlers to handle http requests in a Non-Blocking way.
If I have some logic to be implemented between request and response, how to make this logic to be Non-Blocking too, inside of an undertow handler?
I mean, if it's inserted (or called) within the handleRequest() method is already dispatched to a working thread and then already Non-Blocking or do you need to use CompletableFuture, or Rx Observable or any other reactive library, in order to guarantee that all the stack is reactive?
This is my Handler class as a title of example, I simulate to read a Json which will be parsed into a Person.class object and the transformed (business logic) and then returned back as a Json response.
I've written the two alternatives, in order to understand better how to make the whole stack reactive and Non-Blocking.
Which one do I have to use?
public class DoBusinessLogicHandler implements HttpHandler {
JsonConverter json = JsonConverter.getInstance();
#Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
if (exchange.isInIoThread()) {
exchange.dispatch(this);
return;
}
Pooled<ByteBuffer> pooledByteBuffer = exchange.getConnection().getBufferPool().allocate();
ByteBuffer byteBuffer = pooledByteBuffer.getResource();
byteBuffer.clear();
exchange.getRequestChannel().read(byteBuffer);
int pos = byteBuffer.position();
byteBuffer.rewind();
byte[] bytes = new byte[pos];
byteBuffer.get(bytes);
byteBuffer.clear();
pooledByteBuffer.free();
String requestBody = new String(bytes, Charset.forName("UTF-8") );
/* FIRST ALTERNATIVE:
you can call the business logic directly because the whole body of handleRequest() is managed reactively
*/
Person person = (Person) json.getObjectFromJson(requestBody, Person.class);
Person p = transform(person);
sendResponse(exchange, json.getJsonOf(p));
/* SECOND ALTERNATIVE
you must wrap business logic within a reactive construction (RxJava, CompletableFuture, ecc.) in order to
have all the stack reactive
*/
CompletableFuture
.supplyAsync(()-> (Person) json.getObjectFromJson(requestBody, Person.class))
.thenApply(p -> transform(p))
.thenAccept(p -> sendResponse(exchange, json.getJsonOf(p)));
}
/* it could be also a database fetch or whatever */
private Person transform(Person p){
if(p!=null){
p.setTitle(p.getTitle().toUpperCase());
p.setName(p.getName().toUpperCase());
p.setSurname(p.getSurname().toUpperCase());
}
return p;
}
private void sendResponse(HttpServerExchange exchange, String response){
exchange.getResponseHeaders()
.put(Headers.CONTENT_TYPE, "application/json");
exchange.getResponseSender()
.send(response);
}
}

How to set RequestConfiguration per request using RestTemplate?

I have a library which is being used by customer and they are passing DataRequest object which has userid, timeout and some other fields in it. Now I use this DataRequest object to make a URL and then I make an HTTP call using RestTemplate and my service returns back a JSON response which I use it to make a DataResponse object and return this DataResponse object back to them.
Below is my DataClient class used by customer by passing DataRequest object to it. I am using timeout value passed by customer in DataRequest to timeout the request if it is taking too much time in getSyncData method.
public class DataClient implements Client {
private final RestTemplate restTemplate = new RestTemplate();
private final ExecutorService service = Executors.newFixedThreadPool(10);
// this constructor will be called only once through my factory
// so initializing here
public DataClient() {
try {
restTemplate.setRequestFactory(clientHttpRequestFactory());
} catch (Exception ex) {
// log exception
}
}
#Override
public DataResponse getSyncData(DataRequest key) {
DataResponse response = null;
Future<DataResponse> responseFuture = null;
try {
responseFuture = getAsyncData(key);
response = responseFuture.get(key.getTimeout(), key.getTimeoutUnit());
} catch (TimeoutException ex) {
response = new DataResponse(DataErrorEnum.CLIENT_TIMEOUT, DataStatusEnum.ERROR);
responseFuture.cancel(true);
// logging exception here
}
return response;
}
#Override
public Future<DataResponse> getAsyncData(DataRequest key) {
DataFetcherTask task = new DataFetcherTask(key, restTemplate);
Future<DataResponse> future = service.submit(task);
return future;
}
// how to set socket timeout value by using `key.getSocketTimeout()` instead of using hard coded 400
private ClientHttpRequestFactory clientHttpRequestFactory() {
HttpComponentsClientHttpRequestFactory requestFactory =
new HttpComponentsClientHttpRequestFactory();
RequestConfig requestConfig =
RequestConfig.custom().setConnectionRequestTimeout(400).setConnectTimeout(400)
.setSocketTimeout(400).setStaleConnectionCheckEnabled(false).build();
SocketConfig socketConfig =
SocketConfig.custom().setSoKeepAlive(true).setTcpNoDelay(true).build();
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager =
new PoolingHttpClientConnectionManager();
poolingHttpClientConnectionManager.setMaxTotal(300);
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(200);
CloseableHttpClient httpClientBuilder =
HttpClientBuilder.create().setConnectionManager(poolingHttpClientConnectionManager)
.setDefaultRequestConfig(requestConfig).setDefaultSocketConfig(socketConfig).build();
requestFactory.setHttpClient(httpClientBuilder);
return requestFactory;
}
}
DataFetcherTask class:
public class DataFetcherTask implements Callable<DataResponse> {
private final DataRequest key;
private final RestTemplate restTemplate;
public DataFetcherTask(DataRequest key, RestTemplate restTemplate) {
this.key = key;
this.restTemplate = restTemplate;
}
#Override
public DataResponse call() throws Exception {
// In a nutshell below is what I am doing here.
// 1. Make an url using DataRequest key.
// 2. And then execute the url RestTemplate.
// 3. Make a DataResponse object and return it.
}
}
Customer within our company will use my library like this as shown below by using my factory in their code base -
// if they are calling `getSyncData()` method
DataResponse response = DataClientFactory.getInstance().getSyncData(key);
// and if they want to call `getAsyncData()` method
Future<DataResponse> response = DataClientFactory.getInstance().getAsyncData(key);
I am implementing sync call as async + waiting since I want to throttle them with the number of threads otherwise they can bombard our service without any control.
Problem Statement:-
I am going to add another timeout variable called socket timeout in my DataRequest class and I want to use that variable value (key.getSocketTimeout()) in my clientHttpRequestFactory() method instead of using hard coded 400 value. What is the best and efficient way to do that?
Right now I am using Inversion of Control and passing RestTemplate in a constructor to share the RestTemplate between all my Task objects. I am confuse now how to use key.getSocketTimeout() value in my clientHttpRequestFactory() method. I think this is mostly design question of how to use RestTemplate efficiently here so that I can use key.getSocketTimeout() value in my clientHttpRequestFactory() method.
I have simplified the code so that idea gets clear what I am trying to do and I am on Java 7. Using ThreadLocal is the only option I have here or there is any better and optimized way?
As Peter explains, using ThreadLocal is not a good idea here.
But I also could not find a way to "pass the value up the chain of method calls".
If you use plain "Apache HttpClient", you can create an HttpGet/Put/etc. and simply call
httpRequest.setConfig(myRequestConfig). In other words: set a request configuration per request
(if nothing is set in the request, the request configuration from the HttpClient which executes the request is used).
In contrast, the RestTemplate
calls createRequest(URI, HttpMethod) (defined in HttpAccessor)
which uses the ClientHttpRequestFactory. In other words: there is no option to set a request configuration per request.
I'm not sure why Spring left this option out, it seems a reasonable functional requirement (or maybe I'm still missing something).
Some notes about the "they can bombard our service without any control":
This is one of the reasons to use the PoolingHttpClientConnectionManager:
by setting the appropriate maximum values, there can never be more than the specified maximum connections in use (and thus requests running) at the same time. The assumption here is that you re-use the same RestTemplate instance (and thus connection manager) for each request.
To catch a flood earlier, specify a maximum amount of waiting tasks in the threadpool and set a proper error-handler
(use the workQueue and handler in this constructor).
ThreadLocal is a way to pass dynamic value which normally you would pass via method properties, but you are using an API you can't/don't want to change.
You set the ThreadLocal (possible a data structure containing multiple values) at some level in the thread stack and you can use it further up the stack.
Is this the best approach? NO, you should really pass the value up the chain of method calls, but sometimes this is not practical.
Can you provide an example of how my code will look like with ThreadLocal
You might start with
static final ThreadLocal<Long> SOCKET_TIMEOUT = new ThreadLocal<>();
To set it you can do
SOCKET_TIMEOUT .set(key.getSocketTimeout());
and to get the value you can do
long socketTimeout = SOCKET_TIMEOUT.get();

Categories