1- import { fetch as defaultFetch } from '@whatwg-node/fetch' ;
21import { version } from '../version.js' ;
32import { http } from './http-client.js' ;
43import type { Logger } from './types.js' ;
5- import { CircuitBreakerInterface , createHiveLogger , loadCircuitBreaker } from './utils.js' ;
4+ import { createHiveLogger } from './utils.js' ;
65
76type ReadOnlyResponse = Pick < Response , 'status' | 'text' | 'json' | 'statusText' > ;
87
9- export type AgentCircuitBreakerConfiguration = {
10- /**
11- * Percentage after what the circuit breaker should kick in.
12- * Default: 50
13- */
14- errorThresholdPercentage : number ;
15- /**
16- * Count of requests before starting evaluating.
17- * Default: 5
18- */
19- volumeThreshold : number ;
20- /**
21- * After what time the circuit breaker is attempting to retry sending requests in milliseconds
22- * Default: 30_000
23- */
24- resetTimeout : number ;
25- } ;
26-
27- const defaultCircuitBreakerConfiguration : AgentCircuitBreakerConfiguration = {
28- errorThresholdPercentage : 50 ,
29- volumeThreshold : 10 ,
30- resetTimeout : 30_000 ,
31- } ;
32-
338export interface AgentOptions {
349 enabled ?: boolean ;
3510 name ?: string ;
@@ -74,14 +49,7 @@ export interface AgentOptions {
7449 * WHATWG Compatible fetch implementation
7550 * used by the agent to send reports
7651 */
77- fetch ?: typeof defaultFetch ;
78- /**
79- * Circuit Breaker Configuration.
80- * true -> Use default configuration
81- * false -> Disable
82- * object -> use custom configuration see {AgentCircuitBreakerConfiguration}
83- */
84- circuitBreaker ?: boolean | AgentCircuitBreakerConfiguration ;
52+ fetch ?: typeof fetch ;
8553}
8654
8755export function createAgent < TEvent > (
@@ -100,9 +68,7 @@ export function createAgent<TEvent>(
10068 headers ?( ) : Record < string , string > ;
10169 } ,
10270) {
103- const options : Required < Omit < AgentOptions , 'fetch' | 'circuitBreaker' | 'logger' | 'debug' > > & {
104- circuitBreaker : null | AgentCircuitBreakerConfiguration ;
105- } = {
71+ const options : Required < Omit < AgentOptions , 'fetch' | 'debug' | 'logger' > > = {
10672 timeout : 30_000 ,
10773 enabled : true ,
10874 minTimeout : 200 ,
@@ -112,18 +78,9 @@ export function createAgent<TEvent>(
11278 name : 'hive-client' ,
11379 version,
11480 ...pluginOptions ,
115- circuitBreaker :
116- pluginOptions . circuitBreaker == null || pluginOptions . circuitBreaker === true
117- ? defaultCircuitBreakerConfiguration
118- : pluginOptions . circuitBreaker === false
119- ? null
120- : pluginOptions . circuitBreaker ,
12181 } ;
122-
123- const logger = createHiveLogger ( pluginOptions . logger ?? console , '[agent]' ) ;
124-
82+ const logger = createHiveLogger ( pluginOptions . logger ?? console , '[agent]' , pluginOptions . debug ) ;
12583 const enabled = options . enabled !== false ;
126-
12784 let timeoutID : ReturnType < typeof setTimeout > | null = null ;
12885
12986 function schedule ( ) {
@@ -174,27 +131,6 @@ export function createAgent<TEvent>(
174131 return send ( { throwOnError : true , skipSchedule : true } ) ;
175132 }
176133
177- async function sendHTTPCall ( buffer : string | Buffer < ArrayBufferLike > ) : Promise < Response > {
178- const signal = breaker . getSignal ( ) ;
179- return await http . post ( options . endpoint , buffer , {
180- headers : {
181- accept : 'application/json' ,
182- 'content-type' : 'application/json' ,
183- Authorization : `Bearer ${ options . token } ` ,
184- 'User-Agent' : `${ options . name } /${ options . version } ` ,
185- ...headers ( ) ,
186- } ,
187- timeout : options . timeout ,
188- retry : {
189- retries : options . maxRetries ,
190- factor : 2 ,
191- } ,
192- logger,
193- fetchImplementation : pluginOptions . fetch ,
194- signal,
195- } ) ;
196- }
197-
198134 async function send ( sendOptions ?: {
199135 throwOnError ?: boolean ;
200136 skipSchedule : boolean ;
@@ -212,7 +148,23 @@ export function createAgent<TEvent>(
212148 data . clear ( ) ;
213149
214150 logger . debug ( `Sending report (queue ${ dataToSend } )` ) ;
215- const response = sendFromBreaker ( buffer )
151+ const response = await http
152+ . post ( options . endpoint , buffer , {
153+ headers : {
154+ accept : 'application/json' ,
155+ 'content-type' : 'application/json' ,
156+ Authorization : `Bearer ${ options . token } ` ,
157+ 'User-Agent' : `${ options . name } /${ options . version } ` ,
158+ ...headers ( ) ,
159+ } ,
160+ timeout : options . timeout ,
161+ retry : {
162+ retries : options . maxRetries ,
163+ factor : 2 ,
164+ } ,
165+ logger,
166+ fetchImplementation : pluginOptions . fetch ,
167+ } )
216168 . then ( res => {
217169 logger . debug ( `Report sent!` ) ;
218170 return res ;
@@ -251,74 +203,6 @@ export function createAgent<TEvent>(
251203 } ) ;
252204 }
253205
254- let breaker : CircuitBreakerInterface <
255- Parameters < typeof sendHTTPCall > ,
256- ReturnType < typeof sendHTTPCall >
257- > ;
258- let loadCircuitBreakerPromise : Promise < void > | null = null ;
259- const breakerLogger = createHiveLogger ( logger , '[circuit breaker]' ) ;
260-
261- function noopBreaker ( ) : typeof breaker {
262- return {
263- getSignal ( ) {
264- return undefined ;
265- } ,
266- fire : sendHTTPCall ,
267- } ;
268- }
269-
270- if ( options . circuitBreaker ) {
271- /**
272- * We support Cloudflare, which does not has the `events` module.
273- * So we lazy load opossum which has `events` as a dependency.
274- */
275- breakerLogger . info ( 'initialize circuit breaker' ) ;
276- loadCircuitBreakerPromise = loadCircuitBreaker (
277- CircuitBreaker => {
278- breakerLogger . info ( 'started' ) ;
279- const realBreaker = new CircuitBreaker ( sendHTTPCall , {
280- ...options . circuitBreaker ,
281- timeout : false ,
282- autoRenewAbortController : true ,
283- } ) ;
284-
285- realBreaker . on ( 'open' , ( ) =>
286- breakerLogger . error ( 'circuit opened - backend seems unreachable.' ) ,
287- ) ;
288- realBreaker . on ( 'halfOpen' , ( ) =>
289- breakerLogger . info ( 'circuit half open - testing backend connectivity' ) ,
290- ) ;
291- realBreaker . on ( 'close' , ( ) => breakerLogger . info ( 'circuit closed - backend recovered ' ) ) ;
292-
293- // @ts -expect-error missing definition in typedefs for `opposum`
294- breaker = realBreaker ;
295- } ,
296- ( ) => {
297- breakerLogger . info ( 'circuit breaker not supported on platform' ) ;
298- breaker = noopBreaker ( ) ;
299- } ,
300- ) ;
301- } else {
302- breaker = noopBreaker ( ) ;
303- }
304-
305- async function sendFromBreaker ( ...args : Parameters < typeof breaker . fire > ) {
306- if ( ! breaker ) {
307- await loadCircuitBreakerPromise ;
308- }
309-
310- try {
311- return await breaker . fire ( ...args ) ;
312- } catch ( err : unknown ) {
313- if ( err instanceof Error && 'code' in err && err . code === 'EOPENBREAKER' ) {
314- breakerLogger . info ( 'circuit open - sending report skipped' ) ;
315- return null ;
316- }
317-
318- throw err ;
319- }
320- }
321-
322206 return {
323207 capture,
324208 sendImmediately,
0 commit comments