Should I unsubscribe Observables lists?

I recently encountered a particularly nasty bug related to this concept.

export class AuthService {
  authtoken = new ReplaySubject<string>(1);
  // imagine other things calling `next` to set authorization tokens
}

export class AuthHttpInterceptor implements HttpInterceptor {
  constructor(private _auth: AuthService) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this._auth.authtoken
      .pipe(
        mergeMap((jwt) => {
        let areq = req.clone({setHeaders: {Authorization: 'Bearer ' + jwt}});
        return next.handle(areq);
      }));
  }
}

export class OtherService {
  constructor(private _http: HttpClient) {}

  thingy(): Observable<Thingy> {
    return forkJoin(this._http.get('/thing1'), this._http.get('/thing2').pipe(
      mergeMap(things => frobulate(things))
    );
  }
}

export class Page {
  thingy: Thingy;

  constructor(private _svc: OtherService) {}

  fetchThingy(): void {
    this._svc.thingy().subscribe(thingy => this.thingy = thingy);
  }
}

This is also related to the “diffuse coding bug” topic, because it’s the interceptor that unwittingly causes the bug. OtherService.thingy() will never emit.

After several hours of head-scratching and narrowing, I realized that since the authtoken ReplaySubject never completes, neither will any of the intercepted HTTP requests (although they will emit, which means I didn’t notice the interceptor bug when just simply subscribing to requests, only when attempting to forkJoin multiple ones).

A solution is to add first() to the beginning of the interceptor’s pipe.