1

I have used this pattern to create ServerSentEvent service: Angular and Server Sent Events Here is service code:

import { Injectable, NgZone } from "@angular/core";
import { Observable } from "rxjs";

@Injectable({
  providedIn: "root"
})
export class SseService {
  constructor(private _zone: NgZone) { }

  getServerSentEvent(url: string): Observable<any> {
    return Observable.create(observer => {
      const eventSource = this.getEventSource(url);
      eventSource.onmessage = event => {
        this._zone.run(() => {
          observer.next(event.data);
          console.log(event); // Here I see every received  event
        });
      };
      eventSource.onerror = error => {
        this._zone.run(() => {
          observer.error(error);
          console.log(error);
        });
      };
      // return () => eventSource.close();
    });
  }

  private getEventSource(url: string): EventSource {
    return new EventSource(url);
  }
}

Then I call this stream of ss-events in main component:

ngOnInit() { //This subscribe works just for the first event no more
  this.sseService.getServerSentEvent("http://localhost:8080/ssevents")
    .subscribe(
      data => {
        this.eventmessage = data;
      },
      error => this.error = error
    );

  // But direct next EventSource onmessage() call works here: 
  this.source = new EventSource("http://localhost:8080/ssevents");
  this.source.onmessage = event => {
    this.zone.run(() => {
      this.eventmessage = event.data;
      console.log(event);
    });
  };
  this.source.onerror = error => {
    this.zone.run(() => {
      this.error = error.type;
      console.log(error);
    });
  };
}

Why this internal observable in sseservice does not works? Just first one. So I need use second option - but there I receive permanent error EventTarget (every second or half-second) with no reasons of error description, except Type=error, EventPhase=2. But events are received, that are generated by server just after insertion to mongodb.

Shlang
  • 2,495
  • 16
  • 24
art
  • 59
  • 1
  • 7
  • Please fix formatting – Aluan Haddad May 05 '20 at 17:28
  • I would be happy - but how? Is first streaky grey block incorrect probably, whether the second one? For example when adding code block - Ctrl+ K is less secure then using {{ }} to get at least some kind of formatting text block. And in the second grey block ' ' remains around code. – art May 05 '20 at 22:13

1 Answers1

0

there are could be several issue

  1. try addEventListener instead of onmessage
  2. check message format link
  3. browser can break connection if you have move then 6 connection to same host link

so while you are testing you can exceed it very fast

    @Injectable()
    export class SseService {
      private eventSource: EventSource;

      constructor(private zone: NgZone) {}

      getServerSentEvent(url: string): Observable<MessageEvent> {
        return Observable.create(observer => {
          const eventSource = this.getEventSource(url);
          eventSource.onopen = (ev) => {
            console.log('Connection to server opened.', ev);
          };
          eventSource.onerror = (ev) => {
            console.log('EventSource failed.', ev);
          };
          eventSource.addEventListener('message', event => {
            this.zone.run(() => {
              observer.next(event);
            });
          });
        });
      }

      private getEventSource(url: string): EventSource {
        if (this.eventSource) {
          console.log('EventSource closed.');
          this.eventSource.close();
        }
        this.eventSource = new EventSource(url);
        return this.eventSource;
      }
    }

my test example

Radik
  • 2,715
  • 1
  • 19
  • 24
  • SOLVED: As there was the permanent stream of EventSource errors, regenerated after reconnect probably, passed to Observable error callback, it explains that just one error was delivered to subscriber, and no data - as after the first error - no data and no error! I grasped it after reading it there: https://rxjs-dev.firebaseapp.com/guide/observable -- "In an Observable Execution, zero to infinite Next notifications may be delivered. If either an Error or Complete notification is delivered, then nothing else can be delivered afterwards". So previous state was just due observable execution – art May 12 '20 at 21:05
  • Indeed this sse events are not always delivered as I check it also in Chrome console. So if I trigger event in one Chrome browser window, and recieve sse event in another Chrome browser window, under another user account, there are such combinations - viewed from developer console - sseevent in sending window, and NO in recieving, no in sending - got in receiving window, no sseevents in 2 windows, and very seldom sseevents in 2 browser windows. I need just in receiving so it is even less of 50% cases in practice. Maybe it is due to very bad internet connection when deploying on Heroku – art May 12 '20 at 21:27
  • But 2 weeks ago, before deploying to web (cloud), I tested this events from Chrome rest plugin on localhost. There were series of receiving sse events, but also the series of no events that should be receiving, then - present again. So I though it was due some caching, when events lost. But it has probably no connection to caching. – art May 12 '20 at 21:53
  • As I understand there is permanent loop of EventSource calls to server (but why if it is server sent), succesful when I see such messages (with counter of such messages number) "EventSource finished loading: GET "...app.herokuapp.com/ssseevent". But when i see that one: "EventSource failed loading: GET "...app.herokuapp.com/sseevent", I do understand that in such case no sse event is possible, when sent from server??? – art May 12 '20 at 21:56
  • Maybe also due to permanet loop of such EventSource "finished loading", with frequency of 0.5-1 s, it is not able to catch all sse events, as there is loop of errors and probable reconnection of EventSource. Could anybody to explain me the mechanism??? As I explained solution, but not provided it - I just cast out or commented observer.error() - `this._zone.run(() => { //observer.error(error); console.log(error); })` in EventSource onerorr() in my code. – art May 12 '20 at 22:13