3

I have implemented some error handling code in my main function as below. It uses the catch operator to filter and report on errors in one stream and ignore them in another. This allows me to know about and report on errors that occur with requests whilst not failing the entire stream so that subsequent requests can continue.

For reasons that might not be apparent in the code snippets below I am impementing a custom driver to request and handle data. I'm not using the cycle http driver.

Here's my code that successfully reports an error:

function main(sources) {

    // Catch driver errors so they can be logged
    const error$ = sources.CustomDriver
        .map(x => x.catch(e => Rx.Observable.just(e)))
        .flatMap(p => p)

    // Filter out the errors to deal with requests that did not fail
    const data$ = sources.CustomDriver
        .map(x => x.catch(e => Rx.Observable.empty()))
        .flatMap(p => p)

    return {
        CustomDriver: Rx.Observable.just('initial event'),
        Log: data$,
        Error: error$
    }
}

Cycle.run(main, {
    CustomDriver: makeCustomDriver(),
    Log: msg$ => { msg$.subscribe(
        msg => console.log('LOG: ', msg),
        err => console.log('problem with Log driver: ', err),
        () => console.log('Log Completed')
    ) },
    Error: msg$ => { msg$.subscribe(
        e => console.log('ERR: ', e),
        err => console.log('problem with Error driver:', err),
        () => console.log('Error Completed')
    ) }
})

function makeCustomDriver() {
    return function customDriver(requests$) {
        return requests$
            .map(request => Rx.Observable.fromPromise(makeFailedRequest()))
    }
}

function makeFailedRequest() {
    console.log('some API request')
    return Promise.reject('error')
}

The output is as follows:

some API request
some API request
Log Completed
ERR:  error
Error Completed

On the plus side the error is reported. However, the API request is actually made twice, which is not what I expected to happen initially.

After learning some more RxJS and getting a better understanding of Hot and Cold observables I realised that I was creating two subscriptions to the CustomDriver stream (one for error$ and one for data$) and because the CustomDriver Observable was cold it would repeat the Observable.just for each subscriber.

So I tried to make my CustomDriver Observavble hot with share:

function makeCustomDriver() {
    return function customDriver(requests$) {
        return requests$
            .map(request => Rx.Observable.fromPromise(makeFailedRequest()))
            .share()
    }
}

With that change, the output is as follows:

some API request
Error Completed
Log Completed

So I managed to get rid of the duplicate request but the error was swallowed up in the process.

What is happening with share that causes the errors to be lost and how can I avoid duplicate requests without losing errors?

djskinner
  • 8,035
  • 4
  • 49
  • 72

2 Answers2

2

.shareReplay(1) appears to give the desired result.

djskinner
  • 8,035
  • 4
  • 49
  • 72
1

There is a factory for making custom drivers of that kind that you want (from Promises) https://github.com/whitecolor/cycle-async-driver it includes, helpers for dealing with errors (success and failure).

You can created drivers just like that:

    import {makeAsyncDriver} from 'cycle-async-driver'

    customDriver = makeAsyncDriver(
     (request) => requestHanderThatReturnsPromise(reques)
    )
WHITECOLOR
  • 24,996
  • 37
  • 121
  • 181
  • Thanks. The project README has helped me better understand what is going on and some other caveats when making a custom driver. I'll need some more time to digest it all though. At this stage I'd rather fix my own driver than abstract the boilerplate so I have a better understanding of what's going on. I noticed `replay(null, 1)` and `response$$.connect()` is being used. How does this compare with `shareReplay(1)`? – djskinner May 04 '16 at 11:43
  • connect will immediately start observable, and shareReplay will start when has first observer. Ok, but I advice you to use this factory or you end up of making a like drivers with the same boilerplate code base. – WHITECOLOR May 04 '16 at 15:28