2

每次重试后是否可以动态设置延迟值。我像这样尝试过,但它看起来很精简,它保留了初始设置的值。

imageController(epgData: EpgDataDTO[], showOrMovie: string){
    var retryAfterMilliSeconds = 1000;
    epgData.forEach( (data) => {
        this.getImagesFromMovieDB(data.title).pipe(
            retryWhen((error) => {
                return error.pipe(
                    mergeMap((error: any) => {
                            if(error.response.status === 429) {
                                const retryAfter = error.response.headers;
                                retryAfterMilliSeconds = +retryAfter['retry-after'] * 1000
                                console.log(retryAfterMilliSeconds); // it tells me the correct value here but the retry happens every 1000ms
                                console.log(data.title);
                            }else{
                                this.errorHandling(error)
                                return of("error");
                            }
                            return of("error");
                        }),
                    delay(retryAfterMilliSeconds),
                    take(5)
                )
        }))
        .subscribe( (res) => {
            console.log(res.status);
            console.log(res.headers);

        });
    })
}
4

1 回答 1

2

你非常接近!为了让它工作,我所要做的就是delay(retryAfterMilliSeconds)在操作符的返回值之后移动 tomergeMap()以将它绑定到同一个 observable。没有这个,它会随机延迟返回,mergeMap()而 Observable 实际延迟的返回是随机的。

我把它放在Stackblitz中进行测试。单击最右侧框架底部的“控制台”以查看结果。

这是 StackBlitz 的函数:

imageController(epgData: EpgDataDTO[], showOrMovie: string){
    var retryAfterMilliSeconds = 1000;
    epgData.forEach( (data) => {
        this.getImagesFromMovieDB(data.title).pipe(
            retryWhen((error) => {
                return error.pipe(
                    mergeMap((error: any) => {
                            if(error.response.status === 429) {
                                const retryAfter = error.response.headers;
                                retryAfterMilliSeconds = +retryAfter['retry-after'] * 1000
                                console.log(retryAfterMilliSeconds); // it tells me the correct value here but the retry happens every 1000ms
                                console.log(data.title);
                            }else{
                                this.errorHandling(error)
                                // return of("error"); <-- unnecessary since this will be executed with next statement
                            }
                            return of("error").pipe(delay(retryAfterMilliSeconds));
                        }),
                    // delay(retryAfterMilliSeconds),
                    take(5)
                )
        }))
        .subscribe( 
            (res) => {
                // console.log(res.status);
                // console.log(res.headers);
                const elapsedTime = Math.round(((new Date()).getTime() - startTime) / 1000);
                console.log(`'${res.status}' is Ok - total elapsed time ${elapsedTime} seconds`);
            }
        );
    })
}

其他一些注意事项:

  • return fromgetImagesFromMovieDB()实际上很重要——它需要为每个调用返回一个唯一的 observable 才能使其工作,请确保是这种情况。我在 StackBlitz 中通过构造 Observable return 来模拟这一点delay
  • 如您所见,我更改了 中的第一个函数.subscribe()以打印出为此获取有效数据所花费的总时间res.status。我这样做只是为了显示每次发射它正确地占用了所有延迟的总和。它会在每次失败后重试一段随机时间(我在 5 到 10 秒之间任意选择),由原始函数中的响应标头返回。
  • 小点:你有两个从 mergeMap 返回,return of("error")但第一个是不必要的,因为第二个将立即执行,所以我评论了一个。

我希望这有帮助。

于 2019-01-03T23:39:03.087 回答