'Custom Observable with setInterval with different polling duration

I am new to RxJS / Angular stuff and I am trying to implement a custom Observable for a polling kind of scenario.

Scenario: From a button component in Angular typescript, I want to kickoff polling mechanism on a button click, get some data from an API, return the data back to the button component and based on the response I either want to call next(), complete() or error() on the button component where I actually do .subscribe().

Backend service API method myApi.service.ts

getSomeValue(input: string[]): Observable<MyModel[]> {
    return this.httpClient.get<MyModel[]>(
      `${<some-base-url>}/my-endpoint`,
    );
  }

Polling service polling.service.ts

startPolling(delayInMiliseconds: number): Observable<MyModel> {
    this.myObservable$ = new Observable(observer => {
      this.myInterval= setInterval(() => {
        this.myApi.getSomeValue().subscribe(data => {

          if (<some-condition>) {
            observer.next(status);
          }
          else if (<some-condition>) {
            observer.error();
          }
          else if (<some-condition>) {
            observer.complete();
          }
        });
      }, delayInMiliseconds);
    })
    return this.myObservable$;
  }

button.component.ts

private onButtonClick(): void {
   pollingService.startPolling(originalDelayInMiliseconds)
      .subscribe( 
        (data) => {
          if(data === something) {
            
            console.log("This is the next poll / call to backend API");
            let updatedDelayInMilisecondsInMiliseconds = recalculateDelayInMiliseconds();
            // Do something so that polling continue with new updatedDelayInMilisecondsInMiliseconds 
and I reset the interval defined in pollingService.
          }
        },
        () => {
           console.log("I errored out");
           polllingService.stopInterval(); // This is working
        },
        () => {
          console.log("I am completed");
          polllingService.stopInterval(); // This is working

        }
    )
}

Problem

  1. When the backend service is called first time using observable, it calls with delay of originalDelayInMiliseconds, this is correct and expected.
  2. Now I want to call the same API via observable with the updatedDelayInMilisecondsInMiliseconds. How can I call with the updated time, it gets called with the originalDelayInMiliseconds everytime
  3. I will stop based on some condition but that is not the issue.

Things tried

  1. clearInterval in the next Handler in button component, so that it can take new miliseconds.
  2. calling the same pollingService.startPolling
  3. unsubscribe.
  4. repeatWhen in observable

Please help Any other suggestions??



Solution 1:[1]

class PollingService {
  private pollingSubject = new Subject();

  startPolling(initialDelay: number) {
    this.pollAgain(initialDelay);
    return this.pollingSubject.asObservable();
  }

  pollAgain(delay: number) {
    setTimeout(() => {
      this.pollingSubject.next();
    }, delay);
  }
  stopPolling() {
    this.pollingSubject.complete();
  }
}

used like

 pollingService.startPolling(originalDelayInMiliseconds)
      .subscribe( 
        (data) => {
          if(data === something) {
            
            console.log("This is the next poll / call to backend API");
            let updatedDelayInMilisecondsInMiliseconds = recalculateDelayInMiliseconds();
            pollingService.pollAgain(updatedDelayInMilisecondsInMiliseconds)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Donald Duck