The correlation between subject matter and the workflow of resilience

I am seeking clarity on how Subjects behave when used with the resiliency operators, specifically retry and retryWhen.

The code samples below may differ slightly from the JSBin examples as I have used arrow functions and types for better understanding. This is based on version 4.0.0 - 4.0.7

My expected resiliency behavior is demonstrated in the following example:

Rx.Observable
  .interval(1000)
  .flatMap((count:number) => { 
    return count === 4 ? Rx.Observable.throw('Break') : Rx.Observable.return(count);
  })
  .retry()
  .take(5);

 Output 
 // 0
 // 1
 // 2
 // 3 
 // 0 <-- Retry means we start again from scratch (expected)

After the error occurs on the fourth notification, the entire stream restarts from scratch, maintaining a stateless architecture.

However, adding a multicast operator and an underlying Subject (in this case, a ReplaySubject with a buffer of 1) leads to some confusion, as shown in this example:

const consumer : Rx.Observable<number> = Rx.Observable
  .interval(1000)
  .flatMap((count:number) => { 
    return count === 4 ? Rx.Observable.throw('Break') : Rx.Observable.return(count);
  })
  .shareReplay(1) /* multicast(new Rx.ReplaySubject(1)).refCount() */
  .retry()
  .take(5);

const firstSubscriber : Rx.Disposable = consumer.subscribe((next:number) => {
   console.log('first subscriber: ' + next);
});

setTimeout(() => {
   firstSubscriber.dispose(); /* Lets start fresh in that refCount === 0 */
   const secondSubscriber : Rx.Disposable = consumer.subscribe((next) => {
      console.log('second subscriber: ' + next);
   });
}, 5000 );

Output (before error is thrown)
// "first subscriber: 0"
// "first subscriber: 1"
// "first subscriber: 2"
// "first subscriber: 3"
Output (after error is thrown)
// "first subscriber: 3"
// "second subscriber: 3"
// "second subscriber: 3"
// "second subscriber: 3"
// "second subscriber: 3"
// "second subscriber: 3" 

Upon investigating a Subject, I found that when an error occurs, the subject is marked as inError and each future subscriber will receive the last notification before an onError call is made.

Based on this observation, it seems challenging to use a resilience operator after any other operator containing a Subject (such as shareReplay or publish).

One possible solution could be to create a new Subject whenever an error occurs and a node is disposed. The use of multicast with a factory/subjectSelector could be helpful:

.multicast(() => new Rx.ReplaySubject(1), (source:Rx.ConnectableObservable) => source);

By utilizing a subjectSelector in multicast, a new ConnectableObservable will be created for each new subscription.

It remains uncertain whether sharing and disposing of Subjects will achieve multicasting to subscribers effectively.

In my exploration of this topic, I have even developed a RecoverableReplaySubject that removes the error state upon disposal. However, I recognize that the RxJS team likely has reasons for implementing error handling in their workflow.

Any insights or experiences regarding this issue are highly appreciated.

Thank you.

Answer №1

shareReplay behaves differently in terms of error and completion compared to other subjects. For example, even if the original observable has completed (refCount == 0), shareReplay will not be completed, allowing for replay of past values on further calls. Check out jsbin(shareReplay) vs. jsbin(share).

var source = Rx.Observable
      .interval(100)
      .take(5)
      .shareReplay()

var first = source.subscribe( function(next) {
  console.log('first subscriber: ' + next);
});

setTimeout(function() {
//  first.dispose();
  var second = source.subscribe( function(next) {
  console.log('second subscriber: ' + next);
});

}, 1000 );

You can find more information about the behavior of shareReplay compared to other operators by visiting these links:

The suggested solution was to use a factory function for the multicast operator. It might be worth experimenting with this new design to see if it meets your needs.

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

Retrieving an Angular Application directly from the Server

In order to ensure user authentication from the backend before any other code loads in my Angular app, I need the initial request sent to the backend to check if the user is authenticated. Only once the user has been verified as authenticated can the app b ...

How can I extract a list of errors from this JSON object in a React.js application?

Is there a way to extract the list of errors from the following JSON object using React js? data = { "container_1587015390439_0001_01_000004": { "ERROR":["20/04/16 05:43:51 ERROR CoarseGrainedExecutorBackend: RECEIVED SIGNAL TERM"] , ...

Rails - implementing ajax in partials causing an error: 'cannot find method render'

I am encountering an issue with my form partial located within a div that has the id "chapcomments". The form includes a submit button: <%= f.submit "Post", remote: true %> Within the correct view folder, I have a file named create.js.erb which con ...

Getting attribute values from custom tags in AngularJS is a common task that can be

I am new to AngularJS and I'm having trouble with my code. I am attempting to retrieve the attribute value of post-id from my index.html file and display it in the console from my controller. Here is a snippet from my index.html: <post-creator po ...

Finding the Closest Element with jQuery's .closest() Method

I'm facing an issue while trying to select an element that is positioned above another element. Specifically, I want to target the nearest occurrence of the .discount-dropdown class that appears above the .discount-type class. Can anyone help me figur ...

What could be causing the primeng dialog to appear blank when conducting Jasmine tests on this Angular TypeScript application?

Having trouble testing a component due to rendering issues? Check out the code snippet below: import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from '@angular/core'; @Component({ selector: 'app-help', cha ...

Error encountered during navigation: navigator has not been defined

I encountered an issue where the page gets redirected upon form submission without triggering the catch block. However, in the backend, I am facing an error stating that the API body is not being executed. Below is the code snippet of the page: "use cl ...

What is the reason for sending a single file to the server?

A function called "import File" was developed to send multiple files to the server, but only one file is being received. Input: <input type="files" id="files" name="files" multiple onChange={ (e) => this.importFile(e.target.files) } ...

Ways to Toggle div Visibility for Elements with Identical Class Names on an Individual Basis

After searching for solutions on stackoverflow, I attempted to implement some answers provided by other users, but I'm still not achieving the desired outcome. In my website's about section, there are four different items. When a specific item&a ...

Populate a Textbox Automatically using a Dropdown List

MVC 4 Changing multiple display fields based on DropDownListFor selection Having some issues trying to implement the solution mentioned above. It seems like there might be a problem with either my javascript code or the controller. JavaScript in View ...

Develop a time-sensitive store system using HTML and JavaScript that toggles between open and closed status based on set

I am looking to develop a time-based Open/Closed store using HTML and JavaScript. The concept is that on Fridays, the element with id="friday" should be displayed, otherwise, show the element with id="week". Additionally, if the time i ...

Tips for enabling or disabling elements within an array using React JS

I am looking to develop a feature where I can toggle individual boxes on and off by clicking on them. Currently, only one box at a time can be activated (displayed in green), but I want the ability to control each box independently without affecting the ot ...

Combining AngularJS objects from dual HTTP requests

My goal is to combine two HTTP.get requests into one $scope in order to display the data in the same ng-repeat table. I am utilizing chained promises in my AngularJS application as shown below: AngularJS: function getContainer() { $http.get(" ...

The behavior of CSS position: sticky varies depending on whether the user is scrolling up or scrolling down

I am experiencing an issue in my Vue CLI app where a component with the position: sticky CSS property is being partially hidden under the top of the browser when scrolling down, but works correctly when scrolling up. This behavior is also observed on my Ga ...

Encountering a problem with utilizing the equalTo() method in Firebase Realtime Database in a React

I'm having trouble randomizing and querying a specific node in my database based on the ShopNo When I use equalTo, I can't seem to retrieve the desired node. Instead, I'm only getting a randomized value based on the total number of Shop ent ...

"Optimize Your Data with PrimeNG's Table Filtering Feature

I'm currently working on implementing a filter table using PrimeNG, but I'm facing an issue with the JSON structure I receive, which has multiple nested levels. Here's an example: { "id": "123", "category": "nice", "place": { "ran ...

issue TS2322: The function returns a type of '() => string' which cannot be assigned to type 'string

I have recently started learning Angular 6. Below is the code I am currently working on: export class DateComponent implements OnInit { currentDate: string = new Date().toDateString; constructor() { } ngOnInit() { } } However, I am encounterin ...

Reveal concealed fields following the selection of a specific option

I'm looking to create a bookmarklet that will automatically fill in values when clicked. Currently, I can select values using: document.getElementById('component').value="IAE-Data Agent"; document.getElementById('component').onch ...

Trouble with React routes: only fixed after refreshing the page

import React, { useEffect, useState } from 'react'; import { Container, AppBar, Typography, Grow, Grid, useTheme } from '@material-ui/core'; import { useDispatch } from 'react-redux'; import { BrowserRouter, Router, Route, Swi ...

Combining GET and POST requests in ExpressJS on a single route

As I work on setting up a questionnaire in Express JS with EJS as the renderer, I have already created individual pages for each question. These pages are accessible through static links using the app.get('/question/:number?', routes.questions) f ...