如何让rxjs重试使用websocket连接

时间:2017-10-20 22:26:24

标签: angular websocket rxjs

我正在开发一个需要使用websocket的项目,因此服务器可以快速将数据推送到Web UI。我正在使用Angular v5和angular-cli。但是,当它失败时,我很难让websocket连接重试。

对于那些感兴趣的人,可以找到当前状态的项目here

我跟着this tutorial但是还没有真正掌握rxjs原则。我一直在做很多试验和错误。我现在在哪里。

所以我创建了一个websocket服务来设置Observable

export class WebsocketService {
constructor() { }

private subject: Rx.Subject<MessageEvent>;

public connect(url): Rx.Subject<MessageEvent> {
   if (!this.subject) {
      this.subject = this.create(url);
   }
   return this.subject;
}

private create(url): Rx.Subject<MessageEvent> {
  let ws = new WebSocket(url);

  let observable = Rx.Observable.create(
     (obs: Rx.Observer<MessageEvent>) => {
        ws.onmessage = obs.next.bind(obs);
        ws.onerror = obs.error.bind(obs);
        ws.onclose = obs.complete.bind(obs);
        return ws.close.bind(ws);
     })
  let observer = {
     next: (data: Object) => {
        if (ws.readyState === WebSocket.OPEN) {
           ws.send(JSON.stringify(data));
        }
     }
  }
  return Rx.Subject.create(observer, observable);
 }

}

然后RaceDataService使用WebSocketService将数据映射到有用的地方:

export class RaceDataService {

   public dataStream: Subject<any>;

   constructor(wsService: WebsocketService) {
      this.dataStream = <Subject<any>>wsService
         .connect(ETS_URL)
         .map((response:any): any => {
            let data = JSON.parse(response.data);
            return data
         })
         .retry(3)
   }

   sendAction(action:WebsocketAction) {
      this.dataStream.next(action);
   }
}

最后,我订阅了race-display组件中的observable,如下所示:

constructor(private raceDataService:RaceDataService) {
    raceDataService.dataStream.subscribe(
      msg => {
        console.log("Response from websocket: ");
        console.log(msg);
        if(msg.RaceData) {
          this.HandleCurrentRaceData(msg.RaceData);
        }
      },
      err => {
        this.isConnected = false;
      },
      () => {
        this.sessionEnded = true;
      }
    )
  }

根据我的阅读,在设置可观察对象之后放置.retry(3)应确保在失败后重试连接3次。最终这还不够,我将不得不使用retryWhen()做一些更高级的东西,但此时这个简单的重试甚至不起作用,websocket连接只是尝试了一次而且就是这样。

我真的很感激任何指示。

1 个答案:

答案 0 :(得分:1)

注意在SO问题WebSocket: How to automatically reconnect after it dies中,他们谈到套接字关闭时重新连接。

在您的代码中,retry(3)仅响应通过行ws.onerror = obs.error.bind(obs)发生的事件,但这些只会是套接字处于活动状态时 发生的错误< / EM> 即可。

要使用Rx.retry()重试连接错误,您可能会尝试将websocket onClose挂钩到可观察的onError(ws.onclose = obs.error.bind(obs);),但Rx.retry()只会重新运行wsService.connect(ETS_URL),它将返回主题,它(因为它现在被实例化)不会调用wsService.create()来执行重新打开。

我认为你必须处理websocket级别的重试,而不是在可观察的级别 - 使用附加到onclose的函数,根据引用的问题:

  ws.onclose = function(e) {
    console.log('Socket is closed. Reconnect will be attempted in 1 second.', e.reason);
    setTimeout(function() {
      connect();
    }, 1000);
  };

因此,您有三种类型的错误:

1)重新打开过早关闭的连接

2)重试失败的初始打开,你需要在let ws = new WebSocket(url)周围尝试.catch。

3)ws.onerror发出的连接期间发生的错误。我不确定它们是什么,所以不确定当前的策略(将它们传递给observable)是否最好。请注意,可观察流上的错误将关闭流,因此如果ws错误可忽略(即发生错误消息但后续消息正常),则您不希望流关闭。 / p>