异步任务完成后通知前端

1,396 阅读2分钟

后端异步方法实施结束通知前端

Situation:

异步任务的执行可能非常耗时或者需要依赖其他资源或系统的响应,因此在执行这些任务时,前端客户端不能一直等待其执行完毕。这时候,异步任务的执行一般会放在后端服务器上,等到任务执行完毕后,后端需要将执行结果通知给前端客户端。

常用的方案

轮询:

方式:

前端客户端定时向服务器发出请求,询问任务是否已经完成,如果完成则返回结果给前端

优点与不足

  1. 优点
  • 实现简单无需特殊的服务支持
  • 易于控制频率,避免服务器过载
  • 容错性较强,如果轮训失败,可进行有效的重试
  1. 缺点
  • 增加了带宽损耗
  • 增加了负载与网络流量
  • 互动性不足

websocket

方式:

WebSocket:使用WebSocket技术,建立一个全双工通信的通道,当任务完成时,后端服务器可以通过WebSocket主动向前端客户端发送消息。

优点与不足

  1. 优点
  • 实时性好,可以实现双向通信;
  • 对于推送式的信息(例如即时消息),效果很好
  • 只需要建立一个持久性连接,可以降低网络负载和服务器负载
  1. 不足
  • 实现难度较高
  • 如果消息类型、服务端地址发生变化,需要重新连接;
  • 需要对于运行环境以及网络状况进行更多考虑

实例

🟥 使用轻量级的SimpMessagingTemplate 发送信息 SimpMessageTemplate 基础教程

  1. 全句配置socket 代理适配
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/websocket").setAllowedOriginPatterns("*")
                .withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic");
    }
}
  1. 注入SimpMessagingTemplate 并调用其convertAndSend()方法发送消息
public void importTaskRun(Long daDataImportTaskId) {
    // 获取任务信息
    DaDataImportTask daDataImportTask = daDataImportTaskMapper.selectDaDataImportTaskByDaDataImportTaskId(daDataImportTaskId);

    dataSourceManagerUtils.dataImport(daDataImportTask).whenCompleteAsync((result, throwable) -> {
        if (throwable != null) {
            daDataImportTask.setDaDataImportStatus("3");
            daDataImportTaskMapper.updateDaDataImportTask(daDataImportTask);

        } else {
            daDataImportTask.setDaDataImportStatus("2");
            daDataImportTaskMapper.updateDaDataImportTask(daDataImportTask);
        }
        messagingTemplate.convertAndSend("/topic/message",daDataImportTask.getDaDataImportTaskId() );
    });
}

3.前端构建

mounted() {
  this.socket = new SockJS('http://localhost:16868/websocket');
  this.stompClient = Stomp.over(this.socket);
  this.stompClient.connect({},
    this.onConnected,
    this.onError
  );
},

// 释放socket连接,与订阅
beforeDestroy() {
  if (this.subscription) {
    this.subscription.unsubscribe();
  }
  if (this.stompClient) {
    this.stompClient.disconnect();
  }
},
// socket 链接初始化
onConnected() {
  this.subscription = this.stompClient.subscribe('/topic/message', this.onSubMessage);
},
onError(error) {
  console.log("There is something wrong in socket")
},
// 订阅后端消息
onSubMessage(data) {
  console.log('Data received:', data);
  this.updateTaskExecuteButtonStatusByIndex(data.body)
},
// 更新任务列表中执行按钮的状态
updateTaskExecuteButtonStatusByIndex(rowIndex) {
  // 重新获取数据列表
  this.getList()
},

消息队列

将异步任务的结果封装为消息,发送到消息队列中,后端服务器监听队列,当任务完成后即可将结果传递给前端客户端。