Utilizing RxJS to emit values from an array at specified intervals, triggering a function with each emitted value, and automatically retrying if

I have a problem with handling an array where I need to emit one value every x seconds, call a function with that value, and retry if the function fails. The type of values in the array is not important.

This is what I have implemented so far:

Rx.Observable
    .interval(500)
    .take(arr.length)
    .map(idx => arr[idx])
    .flatMap(dt => randomFunc(dt))
    .catch(e => console.log(e))
    .retry(5)
    .subscribe();

function randomFunc(dt) {
    return Rx.Observable.create(observer => {
        if (dt === 'random') {
            return observer.error(`error`);
        } else {
            return observer.next();
        }
    });
}

However, there are two issues that I am facing:

1: When randomFunc returns an error, the entire chain seems to restart instead of just retrying the failed function.

2: The catch block does not log any errors, despite appearing to retry on error.

To address the first issue, I attempted using switchMap instead of flatMap:

Rx.Observable
    .interval(500)
    .take(arr.length)
    .map(idx => arr[idx])
    .switchMap(dt => randomFunc(dt)
        .catch(e => console.log(e))
        .retry(5)
    )
    .subscribe();

While this appeared to retry only the failed functions, the error logging functionality still did not work. Also, I am unsure if switchMap is appropriate in this context as I am new to Rx programming.

Any assistance or guidance would be greatly appreciated. Thank you!

Answer №1

It's important to note a few key things. The retry() operator simply resubscribes to its source, so if you don't want to restart the entire process, you can merge/concatenate the asynchronous function into the chain.

Rx.Observable.from(arr)
  .concatMap(val => {
    let attempts = 0;

    return Rx.Observable.of(val)
      .delay(500)
      .concatMap(val => randomFunc(val)
        .catch((err, caught) => {
          console.log('log error');
          if (attempts++ === 1) {
            return Rx.Observable.of(err);
          } else {
            return caught;
          }
        })
      );

  })
  .subscribe(val => console.log(val));

function randomFunc(dt) {
  return Rx.Observable.create(observer => {
    if (dt === 'random') {
      observer.error(`error received ${dt}`);
    } else {
      observer.next(dt);
      observer.complete();
    }
  });
}

Check out the live demo: https://jsbin.com/qacamab/7/edit?js,console

This output is logged to the console:

1
2
3
4
log error
log error
error received random
6
7
8
9
10

The catch() operator plays a crucial role in this setup. Its selector function has two arguments:

  • err - The error that occurred
  • caught - The original Observable.

Returning caught from the selector function will result in just resubscribing to the source Observable (effectively equivalent to retry(1)). As you wish to log each error message, using catch() instead of solely relying on retry() is essential. By returning Rx.Observable.of(err), we pass the error along and it will be received by the subscriber as a next notification. Alternatively, returning Observable.empty() would simply ignore the error.

Answer №2

After encountering an error in the function randomFunc, it appears that the entire process restarts from the beginning. Ideally, only the failed part should be retried.

When working with RxJs and combining Observables, errors are propagated and unhandled errors can lead to unsubscription.

The suggestion to use catch within the switchMap is accurate. However, keep in mind that switchMap will only process one Observable at a time; when a new value is mapped, the previous Observable is unsubscribed (or "switched out").

// Creating an Observable from an array
Rx.Observable.from(arr)
    .concatMap(value =>
        // Introducing a 500 ms delay between each value
        Rx.Observable.timer(500).map(_ => value)
    )
    .flatMap(dt =>
        randomFunc(dt)
        .retryWhen(errs =>
            errs
            .do(err => console.error(err))
            // Maximum of 5 retry attempts
            .take(5)
            // Retry after 500ms
            .delay(500)
        )
    )
    .subscribe();

It seems like `catch` does not log any errors even though it retries upon encountering an error.

The function used with `catch` should return an Observable, for example:

Observable.throw(new Error())
    .catch(e =>
        (console.error(e), Observable.of('backup value'))
    )
    .subscribe();

http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-catch

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What steps can be taken to verify values using the console bind function?

Is there a way for developers to check various things in the console while typing code and pressing enter? I attempted to do it but couldn't achieve the desired results. Initially, I added a button on fiddle <button id="test">test< ...

Angular routing with Javascript functionality

I have created a simple Angular Router, but I am facing an issue where the JavaScript is not executing or I am unable to access elements inside the templateUrl. I mostly followed the code from this tutorial, here. Below is my index file: <html ng-app= ...

What is the best method to restrict the size of a div to match the dimensions of the

In my webpage, I have a menubar (div) that contains bookmarks. However, when too many bookmarks are added, the menu becomes too wide for the page size I prefer (1280, 720) and becomes scrollable, causing some bookmarks to be out of view. My goal is to ens ...

Modify the information and return it to me

I am attempting to modify and return the content inside a custom directive (I have found some resources on SO but they only cover replacement). Here is an example: HTML <glossary categoryID="199">Hello and welcome to my site</glossary> JS . ...

Display or conceal a div depending on the selected radio button

I am attempting to display a hidden div based on the input of a radio button. If the "yes" option is checked, the hidden div should be shown. Conversely, if the "no" option is checked, the div should be hidden. I'm not sure why this code isn't w ...

retrieve all entries from a paginated grid

Currently, I am utilizing the datatable feature in bootstrap4 with a table that has pagination set to display 10 items per page. I have implemented a function to retrieve values from the table, however I am facing an issue where I am only able to retriev ...

Unbounded AngularJS 1.x looping of Ag-grid's server-side row model for retrieving infinite rows

I am obtaining a set of rows from the server, along with the lastRowIndex (which is currently at -1, indicating that there are more records available than what is being displayed). The column definition has been created and I can see the column headers in ...

Building a Laravel PHP application that dynamically generates a custom JSON object fetched from the database and passes it from PHP to

I am faced with the task of generating a custom JSON object by organizing data retrieved from PHP in my Controller. I have full control over what information goes where and in what specific order. To accomplish this, it seems like I will need to go throug ...

Navigate a first person simulation using three.js and control your movements with the keyboard arrow

To access my reference material, please go to http://jsfiddle.net/fYtwf/ Overview I am working on a basic 3D simulation using three.js where the camera is surrounded by cubes in three dimensions. These cubes serve as a visual guide to where the camera is ...

Error: Unable to use map function on users .. cannot perform mapping on functions

Initially, the map function in my code was working fine. However, suddenly an error started appearing when I included the users.map line. Surprisingly, if I comment out that line, the code works perfectly again. Even more strangely, if I uncomment it, ev ...

What is the best way to sum the numbers in this code snippet?

I'm trying to iterate through an array called arr = [[1,2],4] using for loops to access the numbers. However, I've noticed that I can't seem to add the last number for some reason. Can anyone explain why this is happening? let arr = [[1, ...

Having issues with inline conditional statements in Angular 5

There is a minor issue that I've been struggling to understand... so In my code, I have an inline if statement like this: <button *ngIf="item?.fields?.assetType !== 'tool' || item?.fields?.assetType !== 'questions'">NEXT< ...

IE is throwing inconsistent responses with the Ajax (XDR) requests

While working on an IE plugin that injects an iframe onto every page, I encountered a problem with making ajax requests. To resolve this, I resorted to using IE's cross domain request instead of jQuery's ajax method, which tends to fail in IE. Su ...

Tips for aligning elements of varying heights

Currently, I am tackling a responsive web design challenge involving floating multiple items in 4 columns side by side. The issue arises due to the varying heights of these items, causing the floating to behave improperly. Here is the current problem illu ...

Angular Directive Fails to Execute Within ng-repeat Loop

In my current configuration, I have: App/Directive var app = angular.module("MyApp", []); app.directive("adminRosterItem", function () { return { restrict: "E", scope: { displayText: "@" }, template: "< ...

User missing in the transition from POST to GET

My journey with Node has just begun, and I decided to delve into the Rocket Rides demo available on GitHub. While exploring the pilot sign-up feature on the web app, I encountered a roadblock when trying to implement a similar functionality for passenger s ...

Set up a Google Map that is added dynamically

I have developed a form with a Google Map that utilizes 'places autocomplete'. I also added a button on the same page to add another location, which creates another map-canvas div. However, when attempting to initialize another instance of the ma ...

I've been struggling with my Create React app for the past two days, and it just won

When trying to create a React project using the command `npx create-react-app reactproject`, I encountered an error: npm ERR! code ENOENT npm ERR! syscall spawn C:\Users\SUJITKUMAR\Desktop npm ERR! path D:\WebDev\React npm ERR! ...

The link in the drop down select is not functioning in IE8/9. When trying to open the drop down select link, an

Could use some help with IE8 and 9 compatibility, can't seem to find a solution. This code works smoothly on Chrome, FF, and Safari. There are two dropdown menus, each with two links. Every dropdown menu has its own "Buy Now" button. Upon selecting ...

What are the ways to convert canvas animations into gif or webm formats?

I've written a function to capture each frame for the GIF, but I'm experiencing laggy output and crashes as the data increases. Any recommendations? function generateGifFromImages(imageList, frameRate, fileName, scaling) { gifshot.createGIF({ ...