RxJs: poll until interval done or correct data received

前端 未结 5 1926
时光取名叫无心
时光取名叫无心 2021-02-02 09:48

How do i execute the following scenario in the browser with RxJs:

  • submit data to queue for processing
  • get back the job id
  • poll another endpoint e
5条回答
  •  不思量自难忘°
    2021-02-02 10:48

    Not your question, but I needed the same functionality

    import { takeWhileInclusive } from 'rxjs-take-while-inclusive'
    import { of, interval, race, throwError } from 'rxjs'
    import { catchError, timeout, mergeMap, delay, switchMapTo } from 'rxjs/operators'
    
    const defaultMaxWaitTimeMilliseconds = 5 * 1000
    
    function isAsyncThingSatisfied(result) {
      return true
    }
    
    export function doAsyncThingSeveralTimesWithTimeout(
      doAsyncThingReturnsPromise,
      maxWaitTimeMilliseconds = defaultMaxWaitTimeMilliseconds,
      checkEveryMilliseconds = 500,
    ) {
      const subject$ = race(
        interval(checkEveryMilliseconds).pipe(
          mergeMap(() => doAsyncThingReturnsPromise()),
          takeWhileInclusive(result => isAsyncThingSatisfied(result)),
        ),
        of(null).pipe(
          delay(maxWaitTimeMilliseconds),
          switchMapTo(throwError('doAsyncThingSeveralTimesWithTimeout timeout'))
        )
      )
    
      return subject$.toPromise(Promise) // will return first result satistieble result of doAsyncThingReturnsPromise or throw error on timeout
    }
    

    Example

    // mailhogWaitForNEmails
    import { takeWhileInclusive } from 'rxjs-take-while-inclusive'
    import { of, interval, race, throwError } from 'rxjs'
    import { catchError, timeout, mergeMap, delay, switchMap } from 'rxjs/operators'
    
    const defaultMaxWaitTimeMilliseconds = 5 * 1000
    
    export function mailhogWaitForNEmails(
      mailhogClient,
      numberOfExpectedEmails,
      maxWaitTimeMilliseconds = defaultMaxWaitTimeMilliseconds,
      checkEveryMilliseconds = 500,
    ) {
      let tries = 0
    
      const mails$ = race(
        interval(checkEveryMilliseconds).pipe(
          mergeMap(() => mailhogClient.getAll()),
          takeWhileInclusive(mails => {
            tries += 1
            return mails.total < numberOfExpectedEmails
          }),
        ),
        of(null).pipe(
          delay(maxWaitTimeMilliseconds),
          switchMap(() => throwError(`mailhogWaitForNEmails timeout after ${tries} tries`))
        )
      )
    
      // toPromise returns promise which contains the last value from the Observable sequence.
      // If the Observable sequence is in error, then the Promise will be in the rejected stage.
      // If the sequence is empty, the Promise will not resolve.
      return mails$.toPromise(Promise)
    }
    
    // mailhogWaitForEmailAndClean
    import { mailhogWaitForNEmails } from './mailhogWaitForNEmails'
    
    export async function mailhogWaitForEmailAndClean(mailhogClient) {
      const mails = await mailhogWaitForNEmails(mailhogClient, 1)
    
      if (mails.count !== 1) {
        throw new Error(
          `Expected to receive 1 email, but received ${mails.count} emails`,
        )
      }
    
      await mailhogClient.deleteAll()
    
      return mails.items[0]
    }
    

提交回复
热议问题