All files / src/api/cloud-volumes/utils jobs.js

85.71% Statements 18/21
70% Branches 14/20
75% Functions 6/8
85.71% Lines 18/21

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90    5x     5x     33x 33x                                             18x     51x       51x 16x     35x 1x     34x       34x   34x 1x                 33x   33x     18x       2x                                  
// @flow
 
import { ServiceError } from '../../../service/error';
import { type Caller, type Job } from '..';
 
const HOUR = 60 * 60 * 1000;
 
function sleep(ms) {
  return new Promise(resolve => {
    global.setTimeout(resolve, ms);
  });
}
 
export interface JobsAPI {
  get(id: string): Promise<Job>;
  finish(
    jobId: string,
    sideEffect: ?(job: Job) => Promise<void>,
    interval: ?number,
    timeout: ?number,
  ): Promise<Job>;
}
 
// eslint-disable-next-line import/prefer-default-export
export async function finish(
  call: Caller,
  jobId: string,
  sideEffect: ?(job: Job) => Promise<void> = null,
  interval: number = 500,
  timeout: number = HOUR,
  interrupt: ?() => boolean = null,
): Promise<Job> {
  const start = Date.now();
 
  function getJob(): Promise<Job> {
    return call('GET', `Jobs/${jobId}`);
  }
 
  async function recursion(job: Job): Promise<Job> {
    if (job.state === 'done') {
      return job;
    }
 
    if (job.state === 'error') {
      throw new ServiceError(500, job.stateDetails, job);
    }
 
    Iif (interrupt && (await interrupt())) {
      return job;
    }
 
    const elapsed = Date.now() - start;
 
    if (elapsed > timeout) {
      throw new ServiceError(
        408,
        `job "${job.action}" for object "${job.objectType}" with id "${
          job.objectId
        }" timed out after ${Math.round(elapsed / 1000)} seconds`,
        job,
      );
    }
 
    await Promise.all([sideEffect && sideEffect(job), sleep(interval)]);
 
    return recursion(await getJob());
  }
 
  return recursion(await getJob());
}
 
export default function jobs(call: Caller): JobsAPI {
  return {
    async get(id) {
      return call('GET', `Jobs/${id}`);
    },
 
    async finish(jobId, sideEffect, interval, timeout, interrupt) {
      return finish(
        call,
        jobId,
        sideEffect,
        interval || 500,
        timeout || HOUR,
        interrupt,
      );
    },
  };
}