Implement asynchrony in java for an endpoint that is blocking while being consulted recurrently by another function

24 views Asked by At

I have this fragment of code that has to be executed repeatedly to validate deployment status

while (true) {
    var logsFlags = devOpsClient.obtainInfoTaskFromRelease(personalToken,  responseCreateRelease.getEnvironments().get(0).getReleaseId(), responseCreateRelease.getEnvironments().get(0).getId());
    if ("inProgress".equalsIgnoreCase(logsFlags.getStatus()) || "queued".equalsIgnoreCase(logsFlags.getStatus())) {
        Thread.sleep(3000);
        Thread.currentThread().
        log.info("Count {}", count++);
        continue;
    } else if ("succeeded".equalsIgnoreCase(logsFlags.getStatus())) {
        break;
    } else if ("rejected".equalsIgnoreCase(logsFlags.getStatus())) {
        throw new Exception("The resource to be displayed failed, check de Logs");
    }
    break;
}
log.info("Status Finished - Resource {} deployed", data.getResource());
        

This makes use of the feign client

@FeignClient(
        value = "devopsCell-svc",
        url = "https://vsrm.dev.azure.com"
)
public interface DevOpsClient {

    @PostMapping("/cell/Deployments-Terraform/_apis/release/releases?api-version=7.1-preview.8")
    ResponseCreateRelease executeManualRelease(
            @RequestHeader("Authorization") String authorizationHeader,
            @RequestBody ReleaseDTO releaseDTO
            );

    @GetMapping("/cell/Deployments-Terraform/_apis/Release/releases/{releaseId}/environments/{environmentId}?api-version=7.1-preview.7")
    DeploymentDTO obtainInfoTaskFromRelease(
            @RequestHeader("Authorization") String authorizationHeader,
            @PathVariable("releaseId") Integer releaseId,
            @PathVariable("environmentId") Integer environmentId
    );

The point is that it is blocking since as I repeatedly consult the status, obtainInfoTaskFromRelease becomes blocked so I would not know how to implement the asynchronous calls and at least that function is no longer blocking, since from the controller it has its own endpoint and is not can run by the above

@PostMapping("/data-deploy")
    public ResponseEntity<String> dataIaCDevOpS(@RequestBody RequestIaCDTO requestList) throws Exception {
        return databaseService.dataIaC(Shield.blindRequestIaCDTO(requestList));
    }

@PostMapping("/obtain-tasks-release")
    public SimplifiedDeploymentDTO responseTaskRelease(@RequestParam(name = "releaseId") Integer releaseId,
                                                       @RequestParam(name = "environmentId") Integer environmentId){
        return databaseService.responseTaskRelease(Integer.valueOf(Shield.blindStr(String.valueOf(releaseId))), Integer.valueOf(Shield.blindStr(String.valueOf(environmentId))));
    }

obtain-tasks-release is an endpoint that consumes obtainInfoTaskFromRelease to show the status, so the current problem is that if the while is repeatedly consulting obtainInfoTaskFromRelease, if I call obtain-tasks-release it will not respond to me until the while does so stop consulting

I appreciate if you can guide me to be able to carry out the process of including some asynchronous solution that does not block the obtainInfoTaskFromRelease function.

1

There are 1 answers

0
Fabian Andres Aspee Encina On

If you want know when is in progress, failed or complete you cannot make this in a single request.

Because the first call can be response with pending but if you want continuiosly the current state, you must call N time the endpoint obtain-tasks-release (polling https://en.wikipedia.org/wiki/Polling_(computer_science)). This method for a personal opinion i don't like.

Another way is make a streaming communication using for example https://www.baeldung.com/java-grpc-streaming

This example is to use the polling communication.


private CompletableFuture<String> methodToCallAnotherService() {

    return CompletableFuture.supplyAsync(() -> devOpsClient.obtainInfoTaskFromRelease(personalToken,
                    responseCreateRelease.getEnvironments().get(0).getReleaseId(), responseCreateRelease.getEnvironments().get(0).getId()))
            .thenApply(logsFlags -> {
                if ("inProgress".equalsIgnoreCase(logsFlags.getStatus()) || "queued".equalsIgnoreCase(logsFlags.getStatus())) {
                    log.info("Count {}", count++);
                    return logsFlags.getStatus();
                } else if ("succeeded".equalsIgnoreCase(logsFlags.getStatus())) {
                    return logsFlags.getStatus();
                } else if ("rejected".equalsIgnoreCase(logsFlags.getStatus())) {
                    return "The resource to be displayed failed, check de Logs";
                } else {
                    return "unknown state";
                }
            });
}

Your endpoint will return a CompletableFuture that will maintain the current state.