@@ -2,20 +2,18 @@ import type { LogFunctions, ProcessingContext } from '@data-fair/lib-common-type
22import type { Account } from '@data-fair/lib-express/index.js'
33import type { Processing , Run } from '#api/types'
44
5- import axios from 'axios'
6- import axiosRetry from 'axios-retry'
75import util from 'node:util'
86import fs from 'fs-extra'
97import path from 'path'
108import resolvePath from 'resolve-path'
119import tmp from 'tmp-promise'
1210import { DataFairWsClient } from '@data-fair/lib-node/ws-client.js'
13- import { httpAgent , httpsAgent } from '@data-fair/lib-node/http-agents.js'
1411import * as wsEmitter from '@data-fair/lib-node/ws-emitter.js'
1512import { decipher } from '@data-fair/processings-shared/cipher.ts'
1613import { running } from '../utils/runs.ts'
1714import config from '#config'
1815import mongo from '#mongo'
16+ import { getAxiosInstance , getHttpErrorMessage , prepareAxiosError } from './axios.ts'
1917
2018fs . ensureDirSync ( config . dataDir )
2119const baseTmpDir = config . tmpDir || path . join ( config . dataDir , 'tmp' )
@@ -27,76 +25,6 @@ let pluginModule: { run: (context: ProcessingContext) => Promise<void>, stop?: (
2725let _stopped : boolean
2826const processingsDir = path . join ( config . dataDir , 'processings' )
2927
30- /**
31- * Create an Axios instance.
32- */
33- const getAxiosInstance = ( processing : Processing ) => {
34- const headers : Record < string , string > = {
35- 'x-apiKey' : config . dataFairAPIKey
36- }
37- if ( config . dataFairAdminMode ) {
38- const account = { ...processing . owner }
39- if ( account . name ) account . name = encodeURIComponent ( account . name )
40- if ( account . departmentName ) account . departmentName = encodeURIComponent ( account . departmentName )
41- headers [ 'x-account' ] = JSON . stringify ( account )
42- }
43- headers [ 'x-processing' ] = JSON . stringify ( { _id : processing . _id , title : encodeURIComponent ( processing . title ) } )
44-
45- const axiosInstance = axios . create ( {
46- // this is necessary to prevent excessive memory usage during large file uploads, see https://github.com/axios/axios/issues/1045
47- maxRedirects : 0 ,
48- httpAgent,
49- httpsAgent
50- } )
51-
52- // apply default base url and send api key when relevant
53- axiosInstance . interceptors . request . use ( cfg => {
54- if ( ! cfg . url ) throw new Error ( 'missing url in axios request' )
55- if ( ! / ^ h t t p s ? : \/ \/ / i. test ( cfg . url ) ) {
56- if ( cfg . url . startsWith ( '/' ) ) cfg . url = config . dataFairUrl + cfg . url
57- else cfg . url = config . dataFairUrl + '/' + cfg . url
58- }
59- const isDataFairUrl = cfg . url . startsWith ( config . dataFairUrl )
60- if ( isDataFairUrl ) Object . assign ( cfg . headers , headers )
61- cfg . headers [ 'User-Agent' ] = cfg . headers [ 'User-Agent' ] ?? `@data-fair/processings (${ processing . plugin } )`
62-
63- // use private data fair url if specified to prevent leaving internal infrastructure
64- // except from GET requests so that they still appear in metrics
65- // except if config.getFromPrivateDataFairUrl is set to true, then all requests are sent to the private url
66- const usePrivate =
67- config . privateDataFairUrl &&
68- isDataFairUrl &&
69- ( config . getFromPrivateDataFairUrl || [ 'post' , 'put' , 'delete' , 'patch' ] . includes ( cfg . method || '' ) )
70- if ( usePrivate ) {
71- cfg . url = cfg . url . replace ( config . dataFairUrl , config . privateDataFairUrl ! )
72- cfg . headers . host = new URL ( config . dataFairUrl ) . host
73- }
74- return cfg
75- } , error => Promise . reject ( error ) )
76-
77- return axiosInstance
78- }
79-
80- // customize axios errors for shorter stack traces when a request fails
81- // WARNING: we used to do it in an interceptor, but it was incompatible with axios-retry
82- const prepareAxiosError = ( error : any ) => {
83- const response = error . response ?? error . request ?. res ?? error . res
84- if ( ! response ) return error
85- delete response . request
86- const headers : Record < string , string > = { }
87- if ( response . headers ?. location ) headers . location = response . headers . location
88- response . headers = headers
89- response . config = response . config ?? error . config
90- if ( response . config ) {
91- response . config = { method : response . config . method , url : response . config . url , params : response . config . params , data : response . config . data }
92- if ( response . config . data && response . config . data . _writableState ) delete response . config . data
93- }
94- if ( response . data && response . data . _readableState ) delete response . data
95- if ( error . message ) response . message = error . message
96- if ( error . stack ) response . stack = error . stack
97- return response
98- }
99-
10028/**
10129 * Create a WebSocket instance.
10230 */
@@ -171,17 +99,7 @@ export const run = async (mailTransport: any) => {
17199 const tmpDir = await tmp . dir ( { unsafeCleanup : true , tmpdir : baseTmpDir , prefix : `processing-run-${ processing . _id } -${ run . _id } ` } )
172100 const processingConfig = processing . config || { }
173101
174- const axiosInstance = getAxiosInstance ( processing )
175- axiosRetry ( axiosInstance , {
176- retries : 3 ,
177- retryDelay : axiosRetry . exponentialDelay ,
178- shouldResetTimeout : true ,
179- onRetry : ( retryCount , _err , requestConfig ) => {
180- const err = prepareAxiosError ( _err )
181- const message = getHttpErrorMessage ( err ) || err . message || err
182- log . warning ( `tentative ${ retryCount } de requête ${ requestConfig . method } ${ requestConfig . url } : ${ message } ` )
183- }
184- } )
102+ const axiosInstance = getAxiosInstance ( processing , log )
185103
186104 const secrets : Record < string , string > = { }
187105 if ( processing . secrets ) {
@@ -254,27 +172,4 @@ export const stop = async () => {
254172 await new Promise ( resolve => setTimeout ( resolve , config . worker . gracePeriod ) )
255173}
256174
257- const getHttpErrorMessage = ( err : any ) => {
258- let httpMessage = err . status ?? err . statusCode
259- if ( httpMessage ) {
260- const statusText = err . statusText ?? err . statusMessage
261- if ( statusText ) httpMessage += ' - ' + statusText
262- if ( err . data ) {
263- if ( typeof err . data === 'string' ) httpMessage += ' - ' + err . data
264- else httpMessage += ' - ' + JSON . stringify ( err . data )
265- } else if ( err . message ) {
266- httpMessage += ' - ' + err . message
267- }
268- if ( err . config && err . config . url ) {
269- let url = err . config . url
270- url = url . replace ( config . dataFairUrl , '' )
271- if ( config . privateDataFairUrl ) {
272- url = url . replace ( config . privateDataFairUrl , '' )
273- }
274- httpMessage += ` (${ url } )`
275- }
276- return httpMessage
277- }
278- }
279-
280175export default { run, stop }
0 commit comments