@@ -115,6 +115,7 @@ export class WebhookController extends EventController implements EventControlle
115115 const httpService = axios . create ( {
116116 baseURL,
117117 headers : webhookHeaders as Record < string , string > | undefined ,
118+ timeout : webhookConfig . REQUEST ?. TIMEOUT_MS ?? 30000 ,
118119 } ) ;
119120
120121 await this . retryWebhookRequest ( httpService , webhookData , `${ origin } .sendData-Webhook` , baseURL , serverUrl ) ;
@@ -156,7 +157,10 @@ export class WebhookController extends EventController implements EventControlle
156157
157158 try {
158159 if ( isURL ( globalURL ) ) {
159- const httpService = axios . create ( { baseURL : globalURL } ) ;
160+ const httpService = axios . create ( {
161+ baseURL : globalURL ,
162+ timeout : webhookConfig . REQUEST ?. TIMEOUT_MS ?? 30000 ,
163+ } ) ;
160164
161165 await this . retryWebhookRequest (
162166 httpService ,
@@ -190,12 +194,21 @@ export class WebhookController extends EventController implements EventControlle
190194 origin : string ,
191195 baseURL : string ,
192196 serverUrl : string ,
193- maxRetries = 10 ,
194- delaySeconds = 30 ,
197+ maxRetries ?: number ,
198+ delaySeconds ?: number ,
195199 ) : Promise < void > {
200+ // Obter configurações de retry das variáveis de ambiente
201+ const webhookConfig = configService . get < Webhook > ( 'WEBHOOK' ) ;
202+ const maxRetryAttempts = maxRetries ?? webhookConfig . RETRY ?. MAX_ATTEMPTS ?? 10 ;
203+ const initialDelay = delaySeconds ?? webhookConfig . RETRY ?. INITIAL_DELAY_SECONDS ?? 5 ;
204+ const useExponentialBackoff = webhookConfig . RETRY ?. USE_EXPONENTIAL_BACKOFF ?? true ;
205+ const maxDelay = webhookConfig . RETRY ?. MAX_DELAY_SECONDS ?? 300 ;
206+ const jitterFactor = webhookConfig . RETRY ?. JITTER_FACTOR ?? 0.2 ;
207+ const nonRetryableStatusCodes = webhookConfig . RETRY ?. NON_RETRYABLE_STATUS_CODES ?? [ 400 , 401 , 403 , 404 , 422 ] ;
208+
196209 let attempts = 0 ;
197210
198- while ( attempts < maxRetries ) {
211+ while ( attempts < maxRetryAttempts ) {
199212 try {
200213 await httpService . post ( '' , webhookData ) ;
201214 if ( attempts > 0 ) {
@@ -208,25 +221,59 @@ export class WebhookController extends EventController implements EventControlle
208221 return ;
209222 } catch ( error ) {
210223 attempts ++ ;
224+
225+ // Verificar se é um erro de timeout
226+ const isTimeout = error . code === 'ECONNABORTED' ;
227+
228+ // Verificar se o erro não deve gerar retry com base no status code
229+ if ( error ?. response ?. status && nonRetryableStatusCodes . includes ( error . response . status ) ) {
230+ this . logger . error ( {
231+ local : `${ origin } ` ,
232+ message : `Erro não recuperável (${ error . response . status } ): ${ error ?. message } . Cancelando retentativas.` ,
233+ statusCode : error ?. response ?. status ,
234+ url : baseURL ,
235+ server_url : serverUrl ,
236+ } ) ;
237+ throw error ;
238+ }
211239
212240 this . logger . error ( {
213241 local : `${ origin } ` ,
214- message : `Tentativa ${ attempts } /${ maxRetries } falhou: ${ error ?. message } ` ,
242+ message : `Tentativa ${ attempts } /${ maxRetryAttempts } falhou: ${ isTimeout ? 'Timeout da requisição' : error ?. message } ` ,
215243 hostName : error ?. hostname ,
216244 syscall : error ?. syscall ,
217245 code : error ?. code ,
246+ isTimeout,
247+ statusCode : error ?. response ?. status ,
218248 error : error ?. errno ,
219249 stack : error ?. stack ,
220250 name : error ?. name ,
221251 url : baseURL ,
222252 server_url : serverUrl ,
223253 } ) ;
224254
225- if ( attempts === maxRetries ) {
255+ if ( attempts === maxRetryAttempts ) {
226256 throw error ;
227257 }
228258
229- await new Promise ( ( resolve ) => setTimeout ( resolve , delaySeconds * 1000 ) ) ;
259+ // Cálculo do delay com backoff exponencial e jitter
260+ let nextDelay = initialDelay ;
261+ if ( useExponentialBackoff ) {
262+ // Fórmula: initialDelay * (2^attempts) com limite máximo
263+ nextDelay = Math . min ( initialDelay * Math . pow ( 2 , attempts - 1 ) , maxDelay ) ;
264+
265+ // Adicionar jitter para evitar "thundering herd"
266+ const jitter = nextDelay * jitterFactor * ( Math . random ( ) * 2 - 1 ) ;
267+ nextDelay = Math . max ( initialDelay , nextDelay + jitter ) ;
268+ }
269+
270+ this . logger . log ( {
271+ local : `${ origin } ` ,
272+ message : `Aguardando ${ nextDelay . toFixed ( 1 ) } segundos antes da próxima tentativa` ,
273+ url : baseURL ,
274+ } ) ;
275+
276+ await new Promise ( ( resolve ) => setTimeout ( resolve , nextDelay * 1000 ) ) ;
230277 }
231278 }
232279 }
0 commit comments