我有一个解析程序用来生成和返回报告的服务。
该服务的初始获取调用了REST端点/report
,该端点在服务器上启动了工作作业,因为该报告占用大量处理器,并且运行需要30秒钟以上。 report
端点返回工作者作业的ID。
然后,我需要使用作业的相关ID轮询工人作业REST端点/job/job_id
。我将继续轮询,直到它返回“完成”状态并包含完成的报告。
此最终输出从服务中返回,解析器使用它。
我无法通过轮询进行此操作。我将对初始报告端点的响应通过管道传递到switchMap中,然后使用时间间隔每隔500ms反复轮询/job/job_id
端点。然后,我尝试使用switchMap轮询答复,如果完成则返回。这是我第一次使用switchMap和polling,所以我不确定我是否正确使用了它。
这是我最近尝试的代码:
getDepartmentReport() {
return this.http
.get<any>(reportUrl, this.getAuthOptions(true))
.pipe(switchMap(initialResponse => {
interval(500).pipe(
switchMap(() => {
return this.http.get<any>(workerUrl + initialResponse.id, this.getAuthOptions(true))
.pipe(
switchMap(pollResponse => {
if(pollResponse.state === 'completed') {
return pollResponse;
}
})
}));
}));
}
这实际上不会编译。它给出以下错误:
Argument of type '(initialResponse: any) => void' is not assignable to parameter of type '(value: any, index: number) => ObservableInput<any>'.
Type 'void' is not assignable to type 'ObservableInput<any>'.
56 .pipe(switchMap(initialResponse => {
我认为发生这种情况是因为在未完成轮询响应时,没有return语句可以处理这种情况,并且返回了空白。
有人有什么想法吗?我很困惑。
答案 0 :(得分:1)
这是一个有趣的问题。
您收到该错误消息是因为switchMap
必须返回一个可观察。在您的代码中,您没有返回任何内容,只是开始了一个间隔。
您还必须告知间隔时间何时停止轮询。这可以在takeWhile
运算符的帮助下实现。为了进一步分离事物,我创建了一个自定义运算符,将在其中进行轮询。
这样操作,您也可以在其他地方重用此运算符。
这是我的方法:
// ===== Server =====
let crtReportId = 1;
let crtReportStatus: { status: string, id: number };
const getReportFromBE = () => {
let initialId = crtReportId;
crtReportStatus = { status: 'pending', id: initialId };
// It takes some time...
timer(2000)
.subscribe(() => crtReportStatus = { status: 'completed', id: initialId })
return of(crtReportId++);
}
const getWorkerStatus = id => of(crtReportStatus);
// ===== Client =====
type CustomPollOperator = (data: any, cond: (d) => boolean, ms: number) => Observable<any>
const pollFor: CustomPollOperator = (data, cond, ms) => {
let shouldPoll = true;
return interval(ms)
.pipe(
tap(() => console.warn('pooling', shouldPoll)),
takeWhile(() => shouldPoll),
switchMap(() => getWorkerStatus(data)),
tap(res => {
if (cond(res)) {
shouldPoll = false;
}
})
)
}
const isWorkerCompleted = w => w.status === 'completed';
const getReports = () => {
return getReportFromBE()
.pipe(
switchMap(workerId => pollFor(workerId,isWorkerCompleted, 200))
)
}
getReports().subscribe((res) => console.log('result', res))