import { SerializableResponse } from 'common' ; import { IOrchestrationFunctionContext , Task } from 'durable-functions/lib/src/classes' ; import _ from 'lodash' ; import { LogLevel } from 'logger' ; import moment from 'moment' ; import { ScanResultResponse , ScanRunErrorResponse , ScanRunResultResponse } from 'service-library' ; import { ActivityAction } from '../contracts/activity-actions' ; import { ActivityActionDispatcher } from './activity-action-dispatcher' ; import { OrchestrationLogger } from './orchestration-logger' ; import { OrchestrationTelemetryProperties } from './orchestration-telemetry-properties' ; import { ScanWaitCondition } from './scan-wait-conditions' ; export class ScanWaitOrchestrator { constructor ( private readonly context , private readonly activityActionDispatcher , private readonly orchestrationLogger ) { } public * waitFor ( scanId , activityName , maxWaitTime , waitTimeInterval , waitConditions ) { const waitStartTime = moment . utc ( this . context . df . currentUtcDateTime ) ; const waitEndTime = waitStartTime . clone ( ) . add ( maxWaitTime , 'seconds' ) ; let scanResultResponse ; let scanStatus ; let completed = false ; this . orchestrationLogger . logOrchestrationStep ( `Starting ${ activityName } orchestration activity` ) ; while ( completed !== true && moment . utc ( this . context . df . currentUtcDateTime ) . isBefore ( waitEndTime ) ) { yield * this . runTimer ( waitTimeInterval , waitStartTime , waitEndTime ) ; scanResultResponse = ( yield * this . activityActionDispatcher . callWebRequestActivity ( ActivityAction . getScanResult , { scanId , } ) ) as SerializableResponse < ScanResultResponse > ; if ( this . scanHasError ( scanResultResponse ) ) { yield * this . onTaskFailure ( scanResultResponse , ActivityAction . getScanResult , { scanId } ) ; } scanStatus = scanResultResponse . body as ScanRunResultResponse ; completed = waitConditions . isSucceeded ( scanStatus ) || waitConditions . isFailed ( scanStatus ) ; } const totalWaitTimeInSeconds = moment . utc ( this . context . df . currentUtcDateTime ) . diff ( moment . utc ( waitStartTime ) , 'seconds' ) ; if ( completed === true && ! waitConditions . isFailed ( scanStatus ) ) { this . orchestrationLogger . logOrchestrationStep ( `Orchestration activity ${ activityName } has succeeded` , LogLevel . info , { totalWaitTimeInSeconds : totalWaitTimeInSeconds . toString ( ) , waitStartTime : waitStartTime . toJSON ( ) , waitEndTime : waitEndTime . toJSON ( ) , } ) ; } else { const traceData = { totalWaitTimeInSeconds : totalWaitTimeInSeconds . toString ( ) , waitStartTime : waitStartTime . toJSON ( ) , waitEndTime : waitEndTime . toJSON ( ) , scanId : scanId , } ; yield * this . onTaskFailure ( scanResultResponse , activityName , traceData ) ; } return scanStatus ; } private * runTimer ( duration , overallStartTime , overallEndTime ) { this . orchestrationLogger . logOrchestrationStep ( `Starting timer with wait time ${ duration }` , LogLevel . info , { waitStartTime : overallStartTime . toJSON ( ) , waitEndTime : overallEndTime . toJSON ( ) , } ) ; const timerOutput = yield this . context . df . createTimer ( moment . utc ( this . context . df . currentUtcDateTime ) . add ( duration , 'seconds' ) . toDate ( ) ) ; this . orchestrationLogger . logOrchestrationStep ( 'Timer completed' , LogLevel . info , { requestResponse : JSON . stringify ( timerOutput ) , waitStartTime : overallStartTime . toJSON ( ) , waitEndTime : overallEndTime . toJSON ( ) , } ) ; } private scanHasError ( response ) { const scanErrorResultResponse = response . body as ScanRunErrorResponse ; return ! _ . isNil ( scanErrorResultResponse . error ) ; } private * onTaskFailure ( response , activityName , traceData ? ) { this . orchestrationLogger . logOrchestrationStep ( `Orchestration activity ${ activityName } has failed` , LogLevel . error , { requestResponse : JSON . stringify ( response ) , ... traceData , } ) ; yield * this . activityActionDispatcher . callTrackAvailability ( false , { activityName : activityName , requestResponse : JSON . stringify ( response ) , } ) ; throw new Error ( `Request failed ${ JSON . stringify ( response ) }` ) ; } }