fix: print a warning when an HTTP request fails

close #1240
PR #2615
This commit is contained in:
Zoltan Kochan
2020-06-08 13:49:54 +03:00
committed by GitHub
parent 16e5044bf8
commit 2ebb7af333
30 changed files with 304 additions and 118 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/fetch": major
"fetch-from-npm-registry": minor
---
Print a warning when request fails and a retry will happen. Breaking changes in the programmatic API of `@pnpm/fetch`.

View File

@@ -0,0 +1,6 @@
---
"@pnpm/core-loggers": minor
"@pnpm/default-reporter": minor
---
New reporter added for request retries.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/tarball-fetcher": minor
---
Print a warning when tarball request fails.

View File

@@ -9,7 +9,7 @@
"test-branch": "pnpm run lint && git remote set-branches --add origin master && git fetch && pnpm run compile && run-p -r verdaccio test-pkgs-branch --workspace-concurrency=2", "test-branch": "pnpm run lint && git remote set-branches --add origin master && git fetch && pnpm run compile && run-p -r verdaccio test-pkgs-branch --workspace-concurrency=2",
"test-pkgs-branch": "cross-env PNPM_REGISTRY_MOCK_UPLINK=http://localhost:7348 pnpm run _test --no-sort --filter=...[origin/master]", "test-pkgs-branch": "cross-env PNPM_REGISTRY_MOCK_UPLINK=http://localhost:7348 pnpm run _test --no-sort --filter=...[origin/master]",
"verdaccio": "verdaccio --config ./verdaccio.yaml --listen 7348", "verdaccio": "verdaccio --config ./verdaccio.yaml --listen 7348",
"compile": "pnpm run --filter @pnpm/fetch compile && pnpm run --filter pnpm compile && pnpm run update-manifests", "compile": "pnpm run --filter pnpm compile && pnpm run update-manifests",
"watch": "pnpm run --filter @pnpm/fetch compile && pnpm run --filter pnpm compile -- --watch", "watch": "pnpm run --filter @pnpm/fetch compile && pnpm run --filter pnpm compile -- --watch",
"coveralls": "lcov-result-merger './packages/*/coverage/lcov.info' | coveralls", "coveralls": "lcov-result-merger './packages/*/coverage/lcov.info' | coveralls",
"update-manifests": "ts-node utils/updater/src/index.ts" "update-manifests": "ts-node utils/updater/src/index.ts"

View File

@@ -12,6 +12,9 @@
{ {
"path": "../error" "path": "../error"
}, },
{
"path": "../fetch"
},
{ {
"path": "../lockfile-types" "path": "../lockfile-types"
}, },

View File

@@ -8,6 +8,7 @@ export * from './linkLogger'
export * from './packageManifestLogger' export * from './packageManifestLogger'
export * from './progressLogger' export * from './progressLogger'
export * from './registryLogger' export * from './registryLogger'
export * from './requestRetryLogger'
export * from './removalLogger' export * from './removalLogger'
export * from './rootLogger' export * from './rootLogger'
export * from './scopeLogger' export * from './scopeLogger'

View File

@@ -11,6 +11,7 @@ import {
PackageManifestLog, PackageManifestLog,
ProgressLog, ProgressLog,
RegistryLog, RegistryLog,
RequestRetryLog,
RootLog, RootLog,
ScopeLog, ScopeLog,
SkippedOptionalDependencyLog, SkippedOptionalDependencyLog,
@@ -19,7 +20,8 @@ import {
SummaryLog, SummaryLog,
} from './all' } from './all'
export type Log = DeprecationLog export type Log =
| DeprecationLog
| FetchingProgressLog | FetchingProgressLog
| HookLog | HookLog
| ImportingLog | ImportingLog
@@ -29,6 +31,7 @@ export type Log = DeprecationLog
| PackageManifestLog | PackageManifestLog
| ProgressLog | ProgressLog
| RegistryLog | RegistryLog
| RequestRetryLog
| RootLog | RootLog
| ScopeLog | ScopeLog
| SkippedOptionalDependencyLog | SkippedOptionalDependencyLog

View File

@@ -0,0 +1,16 @@
import baseLogger, {
LogBase,
} from '@pnpm/logger'
export const requestRetryLogger = baseLogger<RequestRetryMessage>('request-retry')
export interface RequestRetryMessage {
attempt: number,
error: Error,
maxRetries: number,
method: string,
timeout: number,
url: string,
}
export type RequestRetryLog = { name: 'pnpm:request-retry' } & LogBase & RequestRetryMessage

View File

@@ -41,6 +41,7 @@
"most": "^1.8.1", "most": "^1.8.1",
"normalize-path": "3.0.0", "normalize-path": "3.0.0",
"pretty-bytes": "5.3.0", "pretty-bytes": "5.3.0",
"pretty-ms": "^7.0.0",
"pretty-time": "1.1.0", "pretty-time": "1.1.0",
"ramda": "0.27.0", "ramda": "0.27.0",
"right-pad": "1.0.1", "right-pad": "1.0.1",

View File

@@ -93,6 +93,7 @@ export function toOutput$ (
const hookPushStream = new PushStream() const hookPushStream = new PushStream()
const skippedOptionalDependencyPushStream = new PushStream() const skippedOptionalDependencyPushStream = new PushStream()
const scopePushStream = new PushStream() const scopePushStream = new PushStream()
const requestRetryPushStream = new PushStream()
setTimeout(() => { // setTimeout is a workaround for a strange bug in most https://github.com/cujojs/most/issues/491 setTimeout(() => { // setTimeout is a workaround for a strange bug in most https://github.com/cujojs/most/issues/491
opts.streamParser['on']('data', (log: logs.Log) => { opts.streamParser['on']('data', (log: logs.Log) => {
switch (log.name) { switch (log.name) {
@@ -141,6 +142,9 @@ export function toOutput$ (
case 'pnpm:scope': case 'pnpm:scope':
scopePushStream.next(log) scopePushStream.next(log)
break break
case 'pnpm:request-retry':
requestRetryPushStream.next(log)
break
case 'pnpm' as any: // tslint:disable-line case 'pnpm' as any: // tslint:disable-line
case 'pnpm:global' as any: // tslint:disable-line case 'pnpm:global' as any: // tslint:disable-line
case 'pnpm:store' as any: // tslint:disable-line case 'pnpm:store' as any: // tslint:disable-line
@@ -161,6 +165,7 @@ export function toOutput$ (
packageManifest: most.from<logs.PackageManifestLog>(packageManifestPushStream.observable), packageManifest: most.from<logs.PackageManifestLog>(packageManifestPushStream.observable),
progress: most.from<logs.ProgressLog>(progressPushStream.observable), progress: most.from<logs.ProgressLog>(progressPushStream.observable),
registry: most.from<logs.RegistryLog>(registryPushStream.observable), registry: most.from<logs.RegistryLog>(registryPushStream.observable),
requestRetry: most.from<logs.RequestRetryLog>(requestRetryPushStream.observable),
root: most.from<logs.RootLog>(rootPushStream.observable), root: most.from<logs.RootLog>(rootPushStream.observable),
scope: most.from<logs.ScopeLog>(scopePushStream.observable), scope: most.from<logs.ScopeLog>(scopePushStream.observable),
skippedOptionalDependency: most.from<logs.SkippedOptionalDependencyLog>(skippedOptionalDependencyPushStream.observable), skippedOptionalDependency: most.from<logs.SkippedOptionalDependencyLog>(skippedOptionalDependencyPushStream.observable),

View File

@@ -9,6 +9,7 @@ import reportInstallChecks from './reportInstallChecks'
import reportLifecycleScripts from './reportLifecycleScripts' import reportLifecycleScripts from './reportLifecycleScripts'
import reportMisc from './reportMisc' import reportMisc from './reportMisc'
import reportProgress from './reportProgress' import reportProgress from './reportProgress'
import reportRequestRetry from './reportRequestRetry'
import reportScope from './reportScope' import reportScope from './reportScope'
import reportSkippedOptionalDependencies from './reportSkippedOptionalDependencies' import reportSkippedOptionalDependencies from './reportSkippedOptionalDependencies'
import reportStats from './reportStats' import reportStats from './reportStats'
@@ -27,6 +28,7 @@ export default function (
registry: most.Stream<logs.RegistryLog>, registry: most.Stream<logs.RegistryLog>,
root: most.Stream<logs.RootLog>, root: most.Stream<logs.RootLog>,
packageManifest: most.Stream<logs.PackageManifestLog>, packageManifest: most.Stream<logs.PackageManifestLog>,
requestRetry: most.Stream<logs.RequestRetryLog>,
link: most.Stream<logs.LinkLog>, link: most.Stream<logs.LinkLog>,
other: most.Stream<logs.Log>, other: most.Stream<logs.Log>,
hook: most.Stream<logs.HookLog>, hook: most.Stream<logs.HookLog>,
@@ -73,6 +75,7 @@ export default function (
width, width,
}), }),
reportInstallChecks(log$.installCheck, { cwd }), reportInstallChecks(log$.installCheck, { cwd }),
reportRequestRetry(log$.requestRetry),
reportScope(log$.scope, { isRecursive: opts.isRecursive, cmd: opts.cmd }), reportScope(log$.scope, { isRecursive: opts.isRecursive, cmd: opts.cmd }),
reportSkippedOptionalDependencies(log$.skippedOptionalDependency, { cwd }), reportSkippedOptionalDependencies(log$.skippedOptionalDependency, { cwd }),
reportHooks(log$.hook, { cwd, isRecursive: opts.isRecursive }), reportHooks(log$.hook, { cwd, isRecursive: opts.isRecursive }),

View File

@@ -0,0 +1,19 @@
import { RequestRetryLog } from '@pnpm/core-loggers'
import { oneLine } from 'common-tags'
import most = require('most')
import prettyMilliseconds = require('pretty-ms')
import formatWarn from './utils/formatWarn'
export default (
requestRetry$: most.Stream<RequestRetryLog>
) => {
return requestRetry$
.map((log) => {
const retriesLeft = log.maxRetries - log.attempt + 1
const errorCode = log.error['httpStatusCode'] || log.error['status'] || log.error['errno'] || log.error['code']
const msg = oneLine`${log.method} ${log.url} error (${errorCode}).
Will retry in ${prettyMilliseconds(log.timeout, { verbose: true })}.
${retriesLeft} retries left.`
return most.of({ msg: formatWarn(msg) })
})
}

View File

@@ -24,6 +24,7 @@ import test = require('tape')
import './reportingErrors' import './reportingErrors'
import './reportingLifecycleScripts' import './reportingLifecycleScripts'
import './reportingProgress' import './reportingProgress'
import './reportingRequestRetry'
import './reportingScope' import './reportingScope'
const WARN = chalk.bgYellow.black('\u2009WARN\u2009') const WARN = chalk.bgYellow.black('\u2009WARN\u2009')

View File

@@ -0,0 +1,37 @@
import { requestRetryLogger } from '@pnpm/core-loggers'
import { toOutput$ } from '@pnpm/default-reporter'
import {
createStreamParser,
} from '@pnpm/logger'
import chalk = require('chalk')
import test = require('tape')
const WARN = chalk.bgYellow.black('\u2009WARN\u2009')
test('print warning about request retry', (t) => {
const output$ = toOutput$({
context: {
argv: ['install'],
},
streamParser: createStreamParser(),
})
requestRetryLogger.debug({
attempt: 2,
error: new Error(),
maxRetries: 5,
method: 'GET',
timeout: 12500,
url: 'https://foo.bar/qar',
})
t.plan(1)
output$.take(1).subscribe({
complete: () => t.end(),
error: t.end,
next: output => {
t.equal(output, `${WARN} GET https://foo.bar/qar error (undefined). Will retry in 12.5 seconds. 4 retries left.`)
},
})
})

View File

@@ -29,6 +29,9 @@
"url": "https://github.com/pnpm/pnpm/issues" "url": "https://github.com/pnpm/pnpm/issues"
}, },
"homepage": "https://github.com/pnpm/pnpm/blob/master/packages/fetch-from-npm-registry#readme", "homepage": "https://github.com/pnpm/pnpm/blob/master/packages/fetch-from-npm-registry#readme",
"peerDependencies": {
"@pnpm/logger": "^3.1.0"
},
"dependencies": { "dependencies": {
"@pnpm/fetch": "workspace:1.0.3", "@pnpm/fetch": "workspace:1.0.3",
"@pnpm/npm-registry-agent": "workspace:2.0.3" "@pnpm/npm-registry-agent": "workspace:2.0.3"

View File

@@ -1,4 +1,4 @@
import fetch, { Response } from '@pnpm/fetch' import fetch, { isRedirect, Response } from '@pnpm/fetch'
import npmRegistryAgent from '@pnpm/npm-registry-agent' import npmRegistryAgent from '@pnpm/npm-registry-agent'
import { URL } from 'url' import { URL } from 'url'
@@ -62,7 +62,7 @@ export default function (
redirect: 'manual', redirect: 'manual',
retry: defaultOpts.retry, retry: defaultOpts.retry,
}) })
if (!fetch.isRedirect(response.status) || redirects >= MAX_FOLLOWED_REDIRECTS) { if (!isRedirect(response.status) || redirects >= MAX_FOLLOWED_REDIRECTS) {
return response return response
} }

View File

@@ -9,6 +9,9 @@
"../../typings/**/*.d.ts" "../../typings/**/*.d.ts"
], ],
"references": [ "references": [
{
"path": "../fetch"
},
{ {
"path": "../npm-registry-agent" "path": "../npm-registry-agent"
} }

View File

@@ -15,7 +15,7 @@
"lint": "tslint -c ../../tslint.json src/**/*.ts test/**/*.ts", "lint": "tslint -c ../../tslint.json src/**/*.ts test/**/*.ts",
"test": "pnpm run compile", "test": "pnpm run compile",
"prepublishOnly": "pnpm run compile", "prepublishOnly": "pnpm run compile",
"compile": "rimraf lib && tsc && cpy src/**/*.d.ts lib" "compile": "rimraf lib tsconfig.tsbuildinfo && tsc --build"
}, },
"repository": "https://github.com/pnpm/pnpm/blob/master/packages/fetch", "repository": "https://github.com/pnpm/pnpm/blob/master/packages/fetch",
"keywords": [ "keywords": [
@@ -27,13 +27,18 @@
"bugs": { "bugs": {
"url": "https://github.com/pnpm/pnpm/issues" "url": "https://github.com/pnpm/pnpm/issues"
}, },
"peerDependencies": {
"@pnpm/logger": "^3.1.0"
},
"homepage": "https://github.com/pnpm/pnpm/blob/master/packages/fetch#readme", "homepage": "https://github.com/pnpm/pnpm/blob/master/packages/fetch#readme",
"dependencies": { "dependencies": {
"@zeit/fetch-retry": "5.0.0", "@pnpm/core-loggers": "workspace:^4.0.2",
"@zkochan/retry": "^0.2.0",
"node-fetch": "2.6.0", "node-fetch": "2.6.0",
"node-fetch-unix": "2.3.0" "node-fetch-unix": "2.3.0"
}, },
"devDependencies": { "devDependencies": {
"@pnpm/logger": "^3.2.2",
"@types/node-fetch": "^2.5.7", "@types/node-fetch": "^2.5.7",
"cpy-cli": "^3.1.1" "cpy-cli": "^3.1.1"
}, },

View File

@@ -1,48 +0,0 @@
import { Request, RequestInit as NodeRequestInit, Response } from 'node-fetch'
export {
FetchError,
Headers,
HeadersInit,
RequestContext,
RequestMode,
RequestRedirect,
RequestCredentials,
RequestCache,
ResponseType,
ResponseInit,
} from 'node-fetch'
export {
Request,
Response,
}
interface URLLike {
href: string
}
export interface RetryOpts {
factor?: number
maxTimeout?: number
minTimeout?: number
onRetry? (error: unknown): void
retries?: number
}
export interface RequestInit extends NodeRequestInit {
retry?: RetryOpts
onRetry? (error: unknown, opts: RequestInit): void
}
export type RequestInfo = string | URLLike | Request
declare function fetch (
url: RequestInfo,
init?: RequestInit
): Promise<Response>
declare namespace fetch {
function isRedirect (code: number): boolean
}
export default fetch

View File

@@ -1,9 +0,0 @@
const createFetchRetry = require('@zeit/fetch-retry')
const nodeFetch = require('node-fetch-unix')
export default createFetchRetry(nodeFetch)
export const FetchError = nodeFetch.FetchError
export const Headers = nodeFetch.Headers
export const Request = nodeFetch.Request
export const Response = nodeFetch.Response

102
packages/fetch/src/index.ts Normal file
View File

@@ -0,0 +1,102 @@
import { requestRetryLogger } from '@pnpm/core-loggers'
import * as retry from '@zkochan/retry'
import { Request, RequestInit as NodeRequestInit, Response } from 'node-fetch'
import fetch = require('node-fetch-unix')
// retry settings
const MIN_TIMEOUT = 10
const MAX_RETRIES = 5
const MAX_RETRY_AFTER = 20
const FACTOR = 6
export { Response }
export interface RetryOpts {
factor?: number
maxTimeout?: number
minTimeout?: number
retries?: number
}
interface URLLike {
href: string
}
export type RequestInfo = string | URLLike | Request
export interface RequestInit extends NodeRequestInit {
retry?: RetryOpts
}
export const isRedirect = fetch.isRedirect
export default async function fetchRetry (url: RequestInfo, opts: RequestInit = {}): Promise<Response> {
const retryOpts = Object.assign({
factor: FACTOR,
// timeouts will be [10, 60, 360, 2160, 12960]
// (before randomization is added)
maxRetryAfter: MAX_RETRY_AFTER,
minTimeout: MIN_TIMEOUT,
retries: MAX_RETRIES,
}, opts.retry)
const op = retry.operation(retryOpts)
try {
return await new Promise((resolve, reject) => op.attempt(async (attempt) => {
try {
// this will be retried
const res = await fetch(url, opts)
if ((res.status >= 500 && res.status < 600) || res.status === 429) {
throw new ResponseError(res)
} else {
resolve(res)
return
}
} catch (error) {
const timeout = op.retry(error)
if (timeout === false) {
reject(op.mainError())
return
}
requestRetryLogger.debug({
attempt,
error,
maxRetries: retryOpts.retries,
method: opts.method ?? 'GET',
timeout,
url: url.toString(),
})
}
}))
} catch (err) {
if (err instanceof ResponseError) {
return err.res
}
throw err
}
}
class ResponseError extends Error {
public res: Response
public code: number
public status: number
public statusCode: number
public url: string
constructor (res: Response) {
super(res.statusText)
if (Error.captureStackTrace) {
Error.captureStackTrace(this, ResponseError)
}
this.name = this.constructor.name
this.res = res
// backward compat
this.code = this.status = this.statusCode = res.status
this.url = res.url
}
}
exports.ResponseError = ResponseError

View File

@@ -1,14 +1,12 @@
{ {
"extends": "@pnpm/tsconfig", "extends": "@pnpm/tsconfig",
"compilerOptions": { "compilerOptions": {
"allowJs": true, "outDir": "lib",
"checkJs": true, "rootDir": "src"
"composite": false,
"declaration": false,
"outDir": "lib"
}, },
"include": [ "include": [
"src/**/*", "src/**/*",
"../../typings/**/*.d.ts" "../../typings/**/*.d.ts"
] ],
"references": []
} }

View File

@@ -9,6 +9,9 @@
"../../typings/**/*.d.ts" "../../typings/**/*.d.ts"
], ],
"references": [ "references": [
{
"path": "../fetch"
},
{ {
"path": "../resolver-base" "path": "../resolver-base"
} }

View File

@@ -76,12 +76,12 @@
"@types/mz": "^2.7.1", "@types/mz": "^2.7.1",
"@types/ncp": "^2.0.4", "@types/ncp": "^2.0.4",
"@types/ramda": "^0.27.6", "@types/ramda": "^0.27.6",
"@types/retry": "^0.12.0",
"@types/semver": "^7.2.0", "@types/semver": "^7.2.0",
"@types/table": "^5.0.0", "@types/table": "^5.0.0",
"@types/tape-promise": "^4.0.1", "@types/tape-promise": "^4.0.1",
"@types/update-notifier": "^4.1.0", "@types/update-notifier": "^4.1.0",
"@types/which": "^1.3.2", "@types/which": "^1.3.2",
"@zkochan/retry": "^0.2.0",
"@zkochan/rimraf": "1.0.0", "@zkochan/rimraf": "1.0.0",
"anonymous-npm-registry-client": "0.1.2", "anonymous-npm-registry-client": "0.1.2",
"byline": "5.0.0", "byline": "5.0.0",
@@ -101,7 +101,6 @@
"path-exists": "4.0.0", "path-exists": "4.0.0",
"pnpm": "link:", "pnpm": "link:",
"read-yaml-file": "2.0.0", "read-yaml-file": "2.0.0",
"retry": "0.12.0",
"semver": "^7.3.2", "semver": "^7.3.2",
"symlink-dir": "^4.1.0", "symlink-dir": "^4.1.0",
"tape-promise": "4.0.0", "tape-promise": "4.0.0",

View File

@@ -1,8 +1,8 @@
import retry = require('@zkochan/retry')
import loadJsonFile = require('load-json-file') import loadJsonFile = require('load-json-file')
import retry = require('retry')
export default <T>(filePath: string): Promise<T> => { export default <T>(filePath: string): Promise<T> => {
const operation = retry.operation() const operation = retry.operation({})
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
operation.attempt(async (currentAttempt) => { operation.attempt(async (currentAttempt) => {

View File

@@ -9,6 +9,9 @@
"../../typings/**/*.d.ts" "../../typings/**/*.d.ts"
], ],
"references": [ "references": [
{
"path": "../fetch"
},
{ {
"path": "../store-controller-types" "path": "../store-controller-types"
}, },

View File

@@ -34,15 +34,16 @@
"@pnpm/logger": "^3.1.0" "@pnpm/logger": "^3.1.0"
}, },
"dependencies": { "dependencies": {
"@pnpm/core-loggers": "workspace:^4.0.2",
"@pnpm/error": "workspace:1.2.0", "@pnpm/error": "workspace:1.2.0",
"@pnpm/fetcher-base": "workspace:8.0.0", "@pnpm/fetcher-base": "workspace:8.0.0",
"@zkochan/retry": "^0.2.0",
"credentials-by-uri": "2.0.0", "credentials-by-uri": "2.0.0",
"fetch-from-npm-registry": "workspace:4.0.3", "fetch-from-npm-registry": "workspace:4.0.3",
"graceful-fs": "4.2.1", "graceful-fs": "4.2.1",
"mem": "^6.1.0", "mem": "^6.1.0",
"mz": "2.7.0", "mz": "2.7.0",
"path-temp": "2.0.0", "path-temp": "2.0.0",
"retry": "0.12.0",
"rimraf": "3.0.2", "rimraf": "3.0.2",
"ssri": "6.0.1" "ssri": "6.0.1"
}, },

View File

@@ -1,3 +1,4 @@
import { requestRetryLogger } from '@pnpm/core-loggers'
import PnpmError from '@pnpm/error' import PnpmError from '@pnpm/error'
import { import {
Cafs, Cafs,
@@ -5,12 +6,12 @@ import {
FetchResult, FetchResult,
FilesIndex, FilesIndex,
} from '@pnpm/fetcher-base' } from '@pnpm/fetcher-base'
import * as retry from '@zkochan/retry'
import createFetcher from 'fetch-from-npm-registry' import createFetcher from 'fetch-from-npm-registry'
import { IncomingMessage } from 'http' import { IncomingMessage } from 'http'
import fs = require('mz/fs') import fs = require('mz/fs')
import path = require('path') import path = require('path')
import pathTemp = require('path-temp') import pathTemp = require('path-temp')
import retry = require('retry')
import rimraf = require('rimraf') import rimraf = require('rimraf')
import ssri = require('ssri') import ssri = require('ssri')
import urlLib = require('url') import urlLib = require('url')
@@ -97,7 +98,12 @@ export default (
userAgent?: string, userAgent?: string,
} }
): DownloadFunction => { ): DownloadFunction => {
const fetchFromNpmRegistry = createFetcher(gotOpts) // The fetch library can retry requests on bad HTTP responses.
// However, it is not enough to retry on bad HTTP responses only.
// Requests should also be retried when the tarball's integrity check fails.
// Hence, we tell fetch to not retry,
// and we perform the retries from this function instead.
const fetchFromNpmRegistry = createFetcher({ retry: { retries: 0 } })
const retryOpts = { const retryOpts = {
factor: 10, factor: 10,
@@ -130,19 +136,27 @@ export default (
const op = retry.operation(retryOpts) const op = retry.operation(retryOpts)
return new Promise<FetchResult>((resolve, reject) => { return new Promise<FetchResult>((resolve, reject) => {
op.attempt((currentAttempt) => { op.attempt(async (attempt) => {
fetch(currentAttempt) try {
.then(resolve) resolve(await fetch(attempt))
.catch((err) => { } catch (error) {
if (err.httpStatusCode === 403) { if (error.httpStatusCode === 403) {
reject(err) reject(error)
return }
} const timeout = op.retry(error)
if (op.retry(err)) { if (timeout === false) {
return
}
reject(op.mainError()) reject(op.mainError())
return
}
requestRetryLogger.debug({
attempt,
error,
maxRetries: retryOpts.retries,
method: 'GET',
timeout,
url,
}) })
}
}) })
}) })

58
pnpm-lock.yaml generated
View File

@@ -247,6 +247,7 @@ importers:
most: 1.8.1_most@1.8.1 most: 1.8.1_most@1.8.1
normalize-path: 3.0.0 normalize-path: 3.0.0
pretty-bytes: 5.3.0 pretty-bytes: 5.3.0
pretty-ms: 7.0.0
pretty-time: 1.1.0 pretty-time: 1.1.0
ramda: 0.27.0 ramda: 0.27.0
right-pad: 1.0.1 right-pad: 1.0.1
@@ -289,6 +290,7 @@ importers:
normalize-newline: 3.0.0 normalize-newline: 3.0.0
normalize-path: 3.0.0 normalize-path: 3.0.0
pretty-bytes: 5.3.0 pretty-bytes: 5.3.0
pretty-ms: ^7.0.0
pretty-time: 1.1.0 pretty-time: 1.1.0
ramda: 0.27.0 ramda: 0.27.0
right-pad: 1.0.1 right-pad: 1.0.1
@@ -368,15 +370,19 @@ importers:
specifiers: {} specifiers: {}
packages/fetch: packages/fetch:
dependencies: dependencies:
'@zeit/fetch-retry': 5.0.0_node-fetch@2.6.0 '@pnpm/core-loggers': 'link:../core-loggers'
'@zkochan/retry': 0.2.0
node-fetch: 2.6.0 node-fetch: 2.6.0
node-fetch-unix: 2.3.0 node-fetch-unix: 2.3.0
devDependencies: devDependencies:
'@pnpm/logger': 3.2.2
'@types/node-fetch': 2.5.7 '@types/node-fetch': 2.5.7
cpy-cli: 3.1.1 cpy-cli: 3.1.1
specifiers: specifiers:
'@pnpm/core-loggers': 'workspace:^4.0.2'
'@pnpm/logger': ^3.2.2
'@types/node-fetch': ^2.5.7 '@types/node-fetch': ^2.5.7
'@zeit/fetch-retry': 5.0.0 '@zkochan/retry': ^0.2.0
cpy-cli: ^3.1.1 cpy-cli: ^3.1.1
node-fetch: 2.6.0 node-fetch: 2.6.0
node-fetch-unix: 2.3.0 node-fetch-unix: 2.3.0
@@ -2140,12 +2146,12 @@ importers:
'@types/mz': 2.7.1 '@types/mz': 2.7.1
'@types/ncp': 2.0.4 '@types/ncp': 2.0.4
'@types/ramda': 0.27.6 '@types/ramda': 0.27.6
'@types/retry': 0.12.0
'@types/semver': 7.2.0 '@types/semver': 7.2.0
'@types/table': 5.0.0 '@types/table': 5.0.0
'@types/tape-promise': 4.0.1 '@types/tape-promise': 4.0.1
'@types/update-notifier': 4.1.0 '@types/update-notifier': 4.1.0
'@types/which': 1.3.2 '@types/which': 1.3.2
'@zkochan/retry': 0.2.0
'@zkochan/rimraf': 1.0.0 '@zkochan/rimraf': 1.0.0
anonymous-npm-registry-client: 0.1.2 anonymous-npm-registry-client: 0.1.2
byline: 5.0.0 byline: 5.0.0
@@ -2165,7 +2171,6 @@ importers:
path-exists: 4.0.0 path-exists: 4.0.0
pnpm: 'link:' pnpm: 'link:'
read-yaml-file: 2.0.0 read-yaml-file: 2.0.0
retry: 0.12.0
semver: 7.3.2 semver: 7.3.2
symlink-dir: 4.1.0 symlink-dir: 4.1.0
tape-promise: 4.0.0 tape-promise: 4.0.0
@@ -2218,13 +2223,13 @@ importers:
'@types/ncp': ^2.0.4 '@types/ncp': ^2.0.4
'@types/nopt': ^3.0.29 '@types/nopt': ^3.0.29
'@types/ramda': ^0.27.6 '@types/ramda': ^0.27.6
'@types/retry': ^0.12.0
'@types/semver': ^7.2.0 '@types/semver': ^7.2.0
'@types/table': ^5.0.0 '@types/table': ^5.0.0
'@types/tape-promise': ^4.0.1 '@types/tape-promise': ^4.0.1
'@types/update-notifier': ^4.1.0 '@types/update-notifier': ^4.1.0
'@types/which': ^1.3.2 '@types/which': ^1.3.2
'@zkochan/libnpx': 11.0.3 '@zkochan/libnpx': 11.0.3
'@zkochan/retry': ^0.2.0
'@zkochan/rimraf': 1.0.0 '@zkochan/rimraf': 1.0.0
anonymous-npm-registry-client: 0.1.2 anonymous-npm-registry-client: 0.1.2
byline: 5.0.0 byline: 5.0.0
@@ -2253,7 +2258,6 @@ importers:
ramda: 0.27.0 ramda: 0.27.0
read-yaml-file: 2.0.0 read-yaml-file: 2.0.0
render-help: 1.0.0 render-help: 1.0.0
retry: 0.12.0
semver: ^7.3.2 semver: ^7.3.2
split-cmd: 1.0.1 split-cmd: 1.0.1
symlink-dir: ^4.1.0 symlink-dir: ^4.1.0
@@ -2764,15 +2768,16 @@ importers:
symlink-dir: ^4.1.0 symlink-dir: ^4.1.0
packages/tarball-fetcher: packages/tarball-fetcher:
dependencies: dependencies:
'@pnpm/core-loggers': 'link:../core-loggers'
'@pnpm/error': 'link:../error' '@pnpm/error': 'link:../error'
'@pnpm/fetcher-base': 'link:../fetcher-base' '@pnpm/fetcher-base': 'link:../fetcher-base'
'@zkochan/retry': 0.2.0
credentials-by-uri: 2.0.0 credentials-by-uri: 2.0.0
fetch-from-npm-registry: 'link:../fetch-from-npm-registry' fetch-from-npm-registry: 'link:../fetch-from-npm-registry'
graceful-fs: 4.2.1 graceful-fs: 4.2.1
mem: 6.1.0 mem: 6.1.0
mz: 2.7.0 mz: 2.7.0
path-temp: 2.0.0 path-temp: 2.0.0
retry: 0.12.0
rimraf: 3.0.2 rimraf: 3.0.2
ssri: 6.0.1 ssri: 6.0.1
devDependencies: devDependencies:
@@ -2790,6 +2795,7 @@ importers:
tempy: 0.5.0 tempy: 0.5.0
specifiers: specifiers:
'@pnpm/cafs': 'workspace:1.0.1' '@pnpm/cafs': 'workspace:1.0.1'
'@pnpm/core-loggers': 'workspace:^4.0.2'
'@pnpm/error': 'workspace:1.2.0' '@pnpm/error': 'workspace:1.2.0'
'@pnpm/fetcher-base': 'workspace:8.0.0' '@pnpm/fetcher-base': 'workspace:8.0.0'
'@pnpm/logger': 3.2.2 '@pnpm/logger': 3.2.2
@@ -2800,6 +2806,7 @@ importers:
'@types/retry': ^0.12.0 '@types/retry': ^0.12.0
'@types/rimraf': ^3.0.0 '@types/rimraf': ^3.0.0
'@types/ssri': ^6.0.3 '@types/ssri': ^6.0.3
'@zkochan/retry': ^0.2.0
cp-file: 9.0.0 cp-file: 9.0.0
credentials-by-uri: 2.0.0 credentials-by-uri: 2.0.0
fetch-from-npm-registry: 'workspace:4.0.3' fetch-from-npm-registry: 'workspace:4.0.3'
@@ -2808,7 +2815,6 @@ importers:
mz: 2.7.0 mz: 2.7.0
nock: 12.0.3 nock: 12.0.3
path-temp: 2.0.0 path-temp: 2.0.0
retry: 0.12.0
rimraf: 3.0.2 rimraf: 3.0.2
ssri: 6.0.1 ssri: 6.0.1
tempy: 0.5.0 tempy: 0.5.0
@@ -3840,16 +3846,6 @@ packages:
dev: true dev: true
resolution: resolution:
integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==
/@zeit/fetch-retry/5.0.0_node-fetch@2.6.0:
dependencies:
async-retry: 1.3.1
debug: 3.2.6
node-fetch: 2.6.0
dev: false
peerDependencies:
node-fetch: '*'
resolution:
integrity: sha512-48tgGYYNX4AGyR8LZa5nMGdr3j4VXYxAA7BX6RWSKIWZkdh1bbkUB6M9ZLfmxsED0CEGpJmP7svN8qnolwZ45w==
/@zkochan/cmd-shim/4.3.0: /@zkochan/cmd-shim/4.3.0:
dependencies: dependencies:
is-windows: 1.0.2 is-windows: 1.0.2
@@ -3913,6 +3909,11 @@ packages:
dev: false dev: false
resolution: resolution:
integrity: sha512-9hHFHZTOexP/oge2GMQzPlhdi9IJ+Zgnobh7sNfSdIZepULMM/lNQE4hmkFDC2zk8+OBibtfHbUPulNZI18TQA== integrity: sha512-9hHFHZTOexP/oge2GMQzPlhdi9IJ+Zgnobh7sNfSdIZepULMM/lNQE4hmkFDC2zk8+OBibtfHbUPulNZI18TQA==
/@zkochan/retry/0.2.0:
engines:
node: '>=10'
resolution:
integrity: sha512-WhB+2B/ZPlW2Xy/kMJBrMbqecWXcbDDgn0K0wKBAgO2OlBTz1iLJrRWduo+DGGn0Akvz1Lu4Xvls7dJojximWw==
/@zkochan/rimraf/1.0.0: /@zkochan/rimraf/1.0.0:
dependencies: dependencies:
'@types/glob': 7.1.2 '@types/glob': 7.1.2
@@ -4593,12 +4594,6 @@ packages:
node: '>=4' node: '>=4'
resolution: resolution:
integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
/async-retry/1.3.1:
dependencies:
retry: 0.12.0
dev: false
resolution:
integrity: sha512-aiieFW/7h3hY0Bq5d+ktDBejxuwR78vRu9hDUdR8rNhSaQ29VzPL4AoIRG7D/c7tdenwOcKvgPM6tIxB3cB6HA==
/async/3.2.0: /async/3.2.0:
dev: true dev: true
resolution: resolution:
@@ -9751,6 +9746,12 @@ packages:
node: '>=8' node: '>=8'
resolution: resolution:
integrity: sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== integrity: sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==
/parse-ms/2.1.0:
dev: false
engines:
node: '>=6'
resolution:
integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==
/parse-npm-tarball-url/3.0.0: /parse-npm-tarball-url/3.0.0:
dependencies: dependencies:
semver: 6.3.0 semver: 6.3.0
@@ -9999,6 +10000,14 @@ packages:
node: '>=6' node: '>=6'
resolution: resolution:
integrity: sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg== integrity: sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg==
/pretty-ms/7.0.0:
dependencies:
parse-ms: 2.1.0
dev: false
engines:
node: '>=10'
resolution:
integrity: sha512-J3aPWiC5e9ZeZFuSeBraGxSkGMOvulSWsxDByOcbD1Pr75YL3LSNIKIb52WXbCLE1sS5s4inBBbryjF4Y05Ceg==
/pretty-time/1.1.0: /pretty-time/1.1.0:
dev: false dev: false
engines: engines:
@@ -10788,6 +10797,7 @@ packages:
resolution: resolution:
integrity: sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= integrity: sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=
/retry/0.12.0: /retry/0.12.0:
dev: false
engines: engines:
node: '>= 4' node: '>= 4'
resolution: resolution:

View File

@@ -18,7 +18,7 @@ const repoRoot = path.join(__dirname, '../../..')
if (isSubdir(pkgsDir, dir)) { if (isSubdir(pkgsDir, dir)) {
await writeProjectManifest(await updateManifest(dir, manifest)) await writeProjectManifest(await updateManifest(dir, manifest))
} }
if (manifest.name === '@pnpm/fetch' || manifest.name === '@pnpm/tsconfig') continue if (manifest.name === '@pnpm/tsconfig') continue
const relative = path.relative(repoRoot, dir) const relative = path.relative(repoRoot, dir)
const importer = lockfile.importers[relative] const importer = lockfile.importers[relative]
if (!importer) continue if (!importer) continue
@@ -30,7 +30,7 @@ const repoRoot = path.join(__dirname, '../../..')
} }
const references = [] as Array<{ path: string }> const references = [] as Array<{ path: string }>
for (const spec of Object.values(deps)) { for (const spec of Object.values(deps)) {
if (!spec.startsWith('link:') || spec.length === 5 || spec === 'link:../fetch') continue if (!spec.startsWith('link:') || spec.length === 5) continue
references.push({ path: spec.substr(5) }) references.push({ path: spec.substr(5) })
} }
const tsConfig = await loadJsonFile<Object>(tsconfigLoc) const tsConfig = await loadJsonFile<Object>(tsconfigLoc)
@@ -94,11 +94,7 @@ async function updateManifest (dir: string, manifest: ProjectManifest) {
} }
break break
} }
if (manifest.name === '@pnpm/fetch') { scripts.compile = 'rimraf lib tsconfig.tsbuildinfo && tsc --build'
scripts.compile = 'rimraf lib && tsc && cpy src/**/*.d.ts lib'
} else {
scripts.compile = 'rimraf lib tsconfig.tsbuildinfo && tsc --build'
}
delete scripts.tsc delete scripts.tsc
let homepage: string let homepage: string
let repository: string | { type: 'git', url: string } let repository: string | { type: 'git', url: string }