Reputation: 9672
In our Angular websocket service, in order to tell the backend we are still listening, we have to send kind of keep alive signal.
Here is the way we proceed:
@Injectable()
export class WebsocketService {
private ws: CustomWebSocket;
constructor() {
this.ws = new CustomWebSocket('ws://localhost');
this.ws.onOpened(() => {
console.info('WS connected');
this.keepAlive();
});
}
public keepAlive() {
Observable.interval(10000).subscribe((tick: number) => this.ws.send('keep-alive'));
}
}
1 / This service is injected in our main app.module.ts. Do we have to unsubscribe the interval manually or it's safe to allow this infinite observable sequence?
2 / As a general question if we have to unsubscribe, what is the proper way to do it since the subscription is within a service? We don't have the ngOnDestroy
lifecycle hook so how to do it properly?
Upvotes: 1
Views: 1151
Reputation: 20053
Do we have to unsubscribe the interval manually or it's safe to allow this infinite observable sequence?
Typically, if the service is meant to live for the entire lifetime of the app, you wouldn't have to bother since the browser will clean up for you. However, there are some things to consider:
Following the principle of least surprise, a service should clean up after itself when it gets destroyed, so I absolutely would recommend doing so.
We don't have the ngOnDestroy lifecycle hook so how to do it properly?
This is a popular statement, but it is wrong. ngOnDestroy
is also called on services. Straight from the docs:
Lifecycle hook that is called when a directive, pipe or service is destroyed.
So you absolutely can do this:
@Injectable()
export class WebsocketService implements OnDestroy {
private ws: CustomWebSocket;
private destroy$ = new Subject();
constructor() {
this.ws = new CustomWebSocket('ws://localhost');
this.ws.onOpened(() => {
console.info('WS connected');
this.keepAlive();
});
}
public keepAlive() {
Observable.interval(10000)
.takeUntil(this.destroy$)
.subscribe((tick: number) => this.ws.send('keep-alive'));
}
public ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
Upvotes: 3
Reputation: 91
The problem with the service is that there isn't an on destroy method for you to unsubscribe from and it does need to be unsubscribed, only http requests are self closing (the http service does this for you).
I would have your WebsocketService return a cold observable to your main app component.
Create a placeholder for your observable in your main app component IE: ngUnsubscribe: Subject = new Subject();
Subscribe to your observable from your service. IE: WebsocketService.keepAlive().takeUntil(this.ngUnsubscribe).subscribe();
In the onDestroy event in your main app component I would then call this.ngUnsubscribe.next(); this.ngUnsubscribe.complete();
Upvotes: 0