/**
 * Copyright 2020 Opstrace, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ /**
 * Utilities for redux-saga-based task management.
 */ import { call , delay , CallEffect } from "redux-saga/effects" ; import { log } from "./log" ; import { SECOND } from "./time" ; import { ExitError , HighLevelRetry } from "./errors" ; export interface RetryUponAnyErrorParams { task : any ; maxAttempts : number ; doNotLogDetailForTheseErrors : any ; actionName : string ; delaySeconds : number ; } /**
 * Pragmatic retry loop with a specific kind of error handling, see below.
 * Initially moved here because this was shared code between CLI-initiated
 * cluster creation and cluster destruction.
 */ export function * retryUponAnyError ( { task , maxAttempts , doNotLogDetailForTheseErrors , actionName , delaySeconds } ) { let attempt = 0 ; while ( true ) { attempt ++ ; if ( attempt > 1 ) { if ( attempt > maxAttempts ) { throw new ExitError ( 1 , `${ attempt - 1 } attempt(s) failed. Stop retrying. Exit.` ) ; } log . info ( "start attempt %s in %s s" , attempt , delaySeconds ) ; yield delay ( delaySeconds * SECOND ) ; } try { yield call ( task ) ; log . debug ( "task `%s` succeeded (attempt %s)" , actionName , attempt ) ; return ; } catch ( err ) { if ( err instanceof ExitError ) { throw err ; } let logdetail = true ; for ( const etype of doNotLogDetailForTheseErrors ) { if ( err instanceof etype ) { log . debug ( "do not log error detail" ) ; logdetail = false ; break ; } } if ( err instanceof HighLevelRetry ) { log . debug ( "saw HighLevelRetry error: %s" , err . message ) ; logdetail = false ; } if ( logdetail ) { log . error ( "error during %s (attempt %s):\n%s" , actionName , attempt , err ) ; log . debug ( "`err?.stack`: %s" , err ?. stack ) ; try { log . error ( "JSON representation of err: %s" , JSON . stringify ( err , null , 2 ) ) ; } catch ( e ) { log . debug ( "could not json-serialize error: %s" , e ) ; } } } } }