22_ 1. The interface processing method should specify whether it is synchronous or asynchronous, such as uploading pictures from files, returning picture connections and thumbnail links

There is a file upload service, FileService. One of the upload file upload interfaces is particularly slow because the upload interface requires two steps internally. First, upload the original image, and then
Upload thumbnails after compression. If each step takes 5 seconds, the interface needs at least 10 seconds to return.

If the two steps are asynchronous, the following problems will occur

A more reasonable way is to make the upload interface either complete synchronous processing or complete asynchronous processing:

1. in the so-called synchronous processing, the interface must upload the original file and thumbnail synchronously. The caller can choose to timeout the call. If it is too late, it can wait until the upload is completed. If it is too late, it can end the wait and try again next time;
2. the so-called asynchronous processing is a two-stage interface. The upload interface itself only returns a task ID, and then asynchronously performs the upload operation. The upload interface responds quickly. The client needs to call the task query interface with the task ID to query the URL of the uploaded file.

In terms of interface implementation, we also submit the upload task to the thread pool for processing, but we do not synchronously wait for the task to be completed, but write the results to a HashMap after completion. The task query interface obtains the URL of the file by querying the HashMap:

//Counter as ID of upload task
private AtomicInteger atomicInteger = new AtomicInteger(0);

//Temporarily store the results of the upload operation. The production code needs to consider data persistence
private ConcurrentHashMap<String, SyncQueryUploadTaskResponse> downloadUrl = new ConcurrentHashMap<>();

//Asynchronous upload operation
public AsyncUploadResponse asyncUpload(AsyncUploadRequest request) {
	AsyncUploadResponse response = new AsyncUploadResponse();
	//Generate unique upload task ID
	String taskId = "upload" + atomicInteger.incrementAndGet();
	//Asynchronous upload only returns the task ID
	response.setTaskId(taskId);
	//Submit the operation of uploading the original file to the thread pool for asynchronous processing
	threadPool.execute(() -> {
		String url = uploadFile(request.getFile());
	
	//If the ConcurrentHashMap does not contain a Key, initialize a SyncQueryUploadTaskResponse and set DownloadUrl
	downloadUrl.computeIfAbsent(taskId, id -> new SyncQueryUploadTaskResponse(id)).setDownloadUrl(url);
	});
	//Submit the upload thumbnail operation to the thread pool for asynchronous processing
	threadPool.execute(() -> {
		String url = uploadThumbnailFile(request.getFile());
		downloadUrl.computeIfAbsent(taskId, id -> new SyncQueryUploadTaskResponse(id)).setThumbnailDownloadUrl(url);
	});
return response;
}

The file upload query interface takes the task ID as the input parameter and returns the download addresses of the two files. Because the file upload query interface is synchronized, it is directly named syncQueryUploadTask:

//syncQueryUploadTask interface input parameter
@Data
@RequiredArgsConstructor
public class SyncQueryUploadTaskRequest {
	private final String taskId;//Query upload results using upload file task ID
	} /
	
/syncQueryUploadTask Interface output parameter
@Data
@RequiredArgsConstructor
public class SyncQueryUploadTaskResponse {
	private final String taskId; //Task ID
	private String downloadUrl; //Original file download URL
	private String thumbnailDownloadUrl; //Thumbnail Download URL
} 

public SyncQueryUploadTaskResponse syncQueryUploadTask(SyncQueryUploadTaskRequest request) {
	SyncQueryUploadTaskResponse response = new SyncQueryUploadTaskResponse(request.getTaskId());
	//Query results from the previously defined downloadUrl ConcurrentHashMap
	response.setDownloadUrl(downloadUrl.getOrDefault(request.getTaskId(), response).getDownloadUrl());
	response.setThumbnailDownloadUrl(downloadUrl.getOrDefault(request.getTaskId(), response).getThumbnailDownloadUrl());
	return response;
}

The modified FileService no longer provides an upload method that looks like synchronous upload, but internal asynchronous upload. Instead, it provides a very clear:

Use syncQueryUploadTask to query and upload results. The user can select the appropriate method according to the nature of the business: if it is used for back-end batch processing, synchronous uploading can be used, and it is not a problem to wait longer; If it is a user oriented interface, the response time of the interface should not be too long. You can call the asynchronous upload interface, then regularly poll the upload results, and then display the results.

Posted by qo2o on Mon, 30 May 2022 20:23:12 +0530