/**
 * Copyright (c) 2020, 2021 Oracle and/or its affiliates.  All rights reserved.
 * This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license.
 */ import { handleErrorBody , handleErrorResponse } from "./helper" ; import { DefaultRetryCondition } from "./retrier" ; const Breaker = require ( "opossum" ) ; async function FetchWrapper ( req ) { return new Promise ( async ( resolve , reject ) => { try { const response = await fetch ( req ) ; if ( response . status && response . status >= 200 && response . status <= 299 ) { resolve ( { response } ) ; } else { const responseClone = response . clone ( ) ; const errBody = await handleErrorBody ( responseClone ) ; const errorObject = handleErrorResponse ( responseClone , errBody ) ; reject ( { response , errorObject } ) ; } } catch ( e ) { reject ( e ) ; } } ) ; } function defaultErrorFilterFunction ( e ) { console . log ( "error from defaultErrorFunction: " , e ) ; if ( e . code || ( e . errorObject && DefaultRetryCondition . shouldBeRetried ( e . errorObject ) ) ) { return false ; } return true ; } interface CircuitBreakerOptions { timeout ? : number ; resetTimeout ? : number ; rollingCountTimeout ? : number ; rollingCountBuckets ? : number ; name ? : string ; rollingPercentilesEnabled ? : boolean ; capacity ? : number ; errorThresholdPercentage ? : number ; enabled ? : boolean ; allowWarmUp ? : boolean ; volumeThreshold ? : number ; errorFilter ? : Function ; cache ? : boolean ; disableClientCircuitBreaker ? : boolean ; } export default class CircuitBreaker { circuit : any = null ; noCircuit : boolean = false ; static get envVariableCheckForDefaultCircuitBreaker ( ) { if ( process . env . OCI_SDK_DEFAULT_CIRCUITBREAKER_ENABLED === "true" ) { CircuitBreaker . DefaultCircuitBreakerOverriden = true ; } else if ( process . env . OCI_SDK_DEFAULT_CIRCUITBREAKER_ENABLED === "false" ) { CircuitBreaker . DefaultCircuitBreakerOverriden = true ; } return process . env . OCI_SDK_DEFAULT_CIRCUITBREAKER_ENABLED ; } static EnableGlobalCircuitBreaker = true ; static EnableDefaultCircuitBreaker = CircuitBreaker . envVariableCheckForDefaultCircuitBreaker ; public static DefaultCircuitBreakerOverriden = false ; private static DefaultConfiguration : CircuitBreakerOptions = { timeout : 3600000 , errorThresholdPercentage : 80 , resetTimeout : 30000 , rollingCountTimeout : 120000 , rollingCountBuckets : 120 , volumeThreshold : 10 , errorFilter : defaultErrorFilterFunction } ; static get defaultConfiguration ( ) : CircuitBreakerOptions { return CircuitBreaker . DefaultConfiguration ; } static set defaultConfiguration ( circuitBreakerConfig ) { CircuitBreaker . DefaultConfiguration = { ... CircuitBreaker . DefaultConfiguration , ... circuitBreakerConfig } ; CircuitBreaker . DefaultCircuitBreakerOverriden = true ; } static internalCircuit = new Breaker ( FetchWrapper , { timeout : 10000 , errorThresholdPercentage : 50 , resetTimeout : 30000 } ) ; constructor ( options ? ) { if ( options ?. disableClientCircuitBreaker ) { this . noCircuit = true ; return ; } this . circuit = options ? new Breaker ( FetchWrapper , options ) : new Breaker ( FetchWrapper , CircuitBreaker . DefaultConfiguration ) ; this . circuit . on ( "open" , ( ) => { console . log ( "circuit breaker is now in OPEN state" ) ; } ) ; this . circuit . on ( "halfOpen" , ( ) => { console . log ( "circuit breaker is now in HALF OPEN state" ) ; } ) ; this . circuit . on ( "close" , ( ) => { console . log ( "circuit breaker is now in CLOSE state" ) ; } ) ; } }