@cloudbase/node-sdk
Version:
tencent cloud base server sdk for node.js
113 lines (100 loc) • 3.32 kB
text/typescript
import http from 'http'
import request from 'request'
import { IReqOpts } from '../type/index'
import { withRetry, IRetryOptions } from './retry'
import { RequestTimgingsMeasurer } from './request-timings-measurer'
const SAFE_RETRY_CODE_SET = new Set([
'ENOTFOUND',
'ENETDOWN',
'EHOSTDOWN',
'ENETUNREACH',
'EHOSTUNREACH',
'ECONNREFUSED'
])
const RETRY_CODE_SET = new Set([
'ECONNRESET',
'ESOCKETTIMEDOUT'
])
const RETRY_STATUS_CODE_SET = new Set([
])
function shouldRetry(e: any, result: any, operation: any) {
// 重试的错误码
if (e && SAFE_RETRY_CODE_SET.has(e.code)) {
return {
retryAble: true,
message: e.message
}
}
// 连接超时
if (e && e.code === 'ETIMEDOUT' && e.connect === true) {
return {
retryAble: true,
message: e.message
}
}
// 重试的状态码
if (result && RETRY_STATUS_CODE_SET.has(result.statusCode)) {
return {
retryAble: true,
message: `${result.request.method} ${result.request.href} ${result.statusCode} ${http.STATUS_CODES[result.statusCode]}`
}
}
return {
retryAble: false,
message: ''
}
}
interface ITimingsMeasurerOptions {
waitingTime?: number,
interval?: number,
enable?: boolean
}
interface IExtraRequestOptions {
debug?: boolean,
op?: string
seqId?: string,
attempts?: number
timingsMeasurerOptions?: ITimingsMeasurerOptions
retryOptions?: IRetryOptions
}
export function requestWithTimingsMeasure(opts: IReqOpts, extraOptions?: IExtraRequestOptions) {
return new Promise((resolve, reject) => {
const timingsMeasurerOptions: ITimingsMeasurerOptions = extraOptions.timingsMeasurerOptions || {}
const {
waitingTime = 1000,
interval = 200,
enable = !!extraOptions.debug
} = timingsMeasurerOptions
const timingsMeasurer = RequestTimgingsMeasurer.new({
waitingTime,
interval,
enable
})
timingsMeasurer.on('progress', (timings: any, reason = '') => {
const timingsLine = `s:${timings.socket || '-'}|l:${timings.lookup ||
'-'}|c:${timings.connect || '-'}|r:${timings.ready ||
'-'}|w:${timings.waiting || '-'}|d:${timings.download ||
'-'}|e:${timings.end || '-'}|E:${timings.error || '-'}`
console.warn(
`[RequestTimgings][${extraOptions.op || ''}] spent ${Date.now() -
timings.start}ms(${timingsLine}) [${extraOptions.seqId}][${extraOptions.attempts || 1}][${reason}]`
)
})
const clientRequest = request(opts, function(err, response, body) {
return err ? reject(err) : resolve(response)
})
if (clientRequest instanceof request.Request || clientRequest instanceof http.ClientRequest) {
timingsMeasurer.measure(clientRequest)
}
})
}
export function extraRequest(opts: IReqOpts, extraOptions?: IExtraRequestOptions) {
if (extraOptions && extraOptions.retryOptions) {
return withRetry((attempts) => {
return requestWithTimingsMeasure(opts, { ...extraOptions, attempts })
}, { shouldRetry, ...extraOptions.retryOptions })
}
else {
return requestWithTimingsMeasure(opts, { ...extraOptions, attempts: 1 })
}
}