user6073450
user6073450

Reputation: 11

Ngrx polling effects stops working second time

When we start polling everything works as expected. Once we stop and start again $continueRefreshStudents stops working. Please check the stackblitz example.

Steps to Reproduce:

  1. Start Polling (check console logs, polling continues )
  2. Stop Polling
  3. Start Polling 2nd time (This time polling doesn't continue)

https://stackblitz.com/edit/angular-ngrx-polling2?file=src%2Fapp%2Fstate%2Fapp.effects.ts

Upvotes: 1

Views: 333

Answers (3)

Carlos Bensant
Carlos Bensant

Reputation: 297

Thank you @Hopey One, same as OP, I was using takeWhile, but I changed it to use a filter.

And yes, you can use an effect that calls itself with a retries limit, and without a timer.

deliverMessages$ = createEffect(
    () =>
      this.actions$.pipe(
        ofType(MessageActions.addMessage, MessageActions.addMessageSuccess, MessageActions.addMessageFailed),
        withLatestFrom(this.store.select(selectMessages)),
        filter(([_action, messages]) => {
          return messages.length >= 1;
        }),
        switchMap(([_action, messages]) => {
          const payload = messages[0];

          return this.messagesService.addMessage(payload)).pipe(
            map(() => {
              // If Succeed, remove the message from the queue
              return MessageActions.addMessageSuccess(payload)
            }),
            catchError(error => {
              // If Failed, remove the message from the queue (after X retries).
              return MessageActions.addMessageFailed({ error, payload })
            })
          );
        }),
        // Time span between messages
        delay(5000),
      ),
  );

Upvotes: 0

Amer
Amer

Reputation: 6716

You can move takeWhile to the inner observable (within mergeMap) pipe to resolve this issue because in this case, it will complete the inner observable, not the main effect's observable once the isPollingActive is changed:

public continuePolling$ = createEffect(() =>
  this.actions$.pipe(
    ofType(appActions.getDataSuccess),
    tap(data => console.log('app effect continue polling')),
    takeWhile(() => this.isPollingActive),
    delay(2000),
    mergeMap(() =>
      this.appDataSurvice.getData().pipe(
        switchMap(data => {
          return [appActions.getDataSuccess(data)];
        }),
        catchError(err => of(appActions.getDataFail(err))),
        takeWhile(() => this.isPollingActive), // check again incase this has been unset since delay
      )
    )
  )
);

Upvotes: 0

Hopey One
Hopey One

Reputation: 1816

When you use takeWhile it completes the observable in your effect once the stop polling changes the isPollingActive to false. ngrx does not create a new effect each time you start the polling so the subsequent getDataSuccess actions effects don't happen. You can change your takeWhile to filter that way you just ignore the effects when isPollingActive is false.

I'm not sure however that this is the best approach, an action that has an effect that triggers the same action to happen again. I feel like it would be less confusing to have the start action create an interval which could fire a continue action and the stop action stop the interval.

Upvotes: 2

Related Questions