Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: switch httpclient to httpclient2 for retry feature #3606

Merged
merged 2 commits into from
Apr 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/extend/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const proto = module.exports = {
/**
* Shortcut for httpclient.curl
*
* @method Context#curl
* @function Context#curl
* @param {String|Object} url - request url address.
* @param {Object} [options] - options for request.
* @return {Object} see {@link ContextHttpClient#curl}
Expand Down
4 changes: 2 additions & 2 deletions app/extend/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module.exports = {

/**
* Generate URL path(without host) for route. Takes the route name and a map of named params.
* @method Helper#pathFor
* @function Helper#pathFor
* @param {String} name - Router Name
* @param {Object} params - Other params
*
Expand All @@ -25,7 +25,7 @@ module.exports = {

/**
* Generate full URL(with host) for route. Takes the route name and a map of named params.
* @method Helper#urlFor
* @function Helper#urlFor
* @param {String} name - Router name
* @param {Object} params - Other params
* @example
Expand Down
18 changes: 14 additions & 4 deletions app/extend/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ module.exports = {
},

/**
* Get or set the request remote IPv4 address
* Get the request remote IPv4 address
* @member {String} Request#ip
* @param {String} ip - IPv4 address
* @return {String} IPv4 address
* @example
* ```js
* this.request.ip
Expand All @@ -116,6 +116,17 @@ module.exports = {
return this._ip;
},

/**
* Set the request remote IPv4 address
* @member {String} Request#ip
* @param {String} ip - IPv4 address
* @example
* ```js
* this.request.ip
* => '127.0.0.1'
* => '111.10.2.1'
* ```
*/
set ip(ip) {
this._ip = ip;
},
Expand Down Expand Up @@ -226,10 +237,9 @@ module.exports = {
/**
* Set query-string as an object.
*
* @method Request#query
* @function Request#query
* @param {Object} obj set querystring and query object for request.
* @return {void}
* @api public
*/
set query(obj) {
this.querystring = querystring.stringify(obj);
Expand Down
12 changes: 11 additions & 1 deletion app/extend/response.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ module.exports = {
* And access log should save 500 not 302,
* then the `realStatus` can help us find out the real status code.
* @member {Number} Response#realStatus
* @param {Number} status The status code to be set.
* @return {Number} The status code to be set.
*/
get realStatus() {
if (this[REAL_STATUS]) {
Expand All @@ -85,6 +85,16 @@ module.exports = {
return this.status;
},

/**
* Set a real status code.
*
* e.g.: Using 302 status redirect to the global error page
* instead of show current 500 status page.
* And access log should save 500 not 302,
* then the `realStatus` can help us find out the real status code.
* @member {Number} Response#realStatus
* @param {Number} status The status code to be set.
*/
set realStatus(status) {
this[REAL_STATUS] = status;
},
Expand Down
12 changes: 6 additions & 6 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ import { Readable } from 'stream';
import { Socket } from 'net';
import { IncomingMessage, ServerResponse } from 'http';
import { EggLogger, EggLoggers, LoggerLevel as EggLoggerLevel, EggContextLogger } from 'egg-logger';
import { HttpClient2, RequestOptions } from 'urllib';
import { HttpClient2, RequestOptions2 as RequestOptions } from 'urllib';
import {
EggCoreBase,
FileLoaderOption,
EggLoader as CoreLoader,
EggCoreOptions as CoreOptions,
EggLoaderOptions as CoreLoaderOptions,
EggLoader as CoreLoader,
EggCoreOptions as CoreOptions,
EggLoaderOptions as CoreLoaderOptions,
BaseContextClass as CoreBaseContextClass,
} from 'egg-core';
import EggCookies = require('egg-cookies');
Expand Down Expand Up @@ -636,7 +636,7 @@ declare module 'egg' {

truncated: boolean;
}

interface GetFileStreamOptions {
requireFile?: boolean; // required file submit, default is true
defCharset?: string;
Expand Down Expand Up @@ -664,7 +664,7 @@ declare module 'egg' {
* special properties (e.g: encrypted). So we must remove this property and
* create our own with the same name.
* @see https://github.com/eggjs/egg/pull/2958
*
*
* However, the latest version of Koa has "[key: string]: any" on the
* context, and there'll be a type error for "keyof koa.Context".
* So we have to directly inherit from "KoaApplication.BaseContext" and
Expand Down
2 changes: 1 addition & 1 deletion lib/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const EGG_PATH = Symbol.for('egg#eggPath');
*/
class Agent extends EggApplication {
/**
* @constructor
* @class
* @param {Object} options - see {@link EggApplication}
*/
constructor(options = {}) {
Expand Down
2 changes: 1 addition & 1 deletion lib/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function escapeHeaderValue(value) {
class Application extends EggApplication {

/**
* @constructor
* @class
* @param {Object} options - see {@link EggApplication}
*/
constructor(options = {}) {
Expand Down
6 changes: 5 additions & 1 deletion lib/core/base_context_logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const CALL = Symbol('BaseContextLogger#call');
class BaseContextLogger {

/**
* @constructor
* @class
* @param {Context} ctx - context instance
* @param {String} pathName - class path name
* @since 1.0.0
Expand All @@ -29,6 +29,7 @@ class BaseContextLogger {

/**
* @member {Function} BaseContextLogger#debug
* @param {...any} args - log msg
* @since 1.2.0
*/
debug(...args) {
Expand All @@ -37,6 +38,7 @@ class BaseContextLogger {

/**
* @member {Function} BaseContextLogger#info
* @param {...any} args - log msg
* @since 1.2.0
*/
info(...args) {
Expand All @@ -45,6 +47,7 @@ class BaseContextLogger {

/**
* @member {Function} BaseContextLogger#warn
* @param {...any} args - log msg
* @since 1.2.0
*/
warn(...args) {
Expand All @@ -53,6 +56,7 @@ class BaseContextLogger {

/**
* @member {Function} BaseContextLogger#error
* @param {...any} args - log msg
* @since 1.2.0
*/
error(...args) {
Expand Down
2 changes: 1 addition & 1 deletion lib/core/httpclient.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const HttpsAgent = require('agentkeepalive').HttpsAgent;
const urllib = require('urllib');
const ms = require('humanize-ms');

class HttpClient extends urllib.HttpClient {
class HttpClient extends urllib.HttpClient2 {
constructor(app) {
normalizeConfig(app);
const config = app.config.httpclient;
Expand Down
4 changes: 2 additions & 2 deletions lib/egg.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const CLUSTER_CLIENTS = Symbol.for('egg#clusterClients');
class EggApplication extends EggCore {

/**
* @constructor
* @class
* @param {Object} options
* - {Object} [type] - type of instance, Agent and Application both extend koa, type can determine what it is.
* - {String} [baseDir] - app root dir, default is `process.cwd()`
Expand Down Expand Up @@ -508,7 +508,7 @@ class EggApplication extends EggCore {

/**
* Create egg context
* @method EggApplication#createContext
* @function EggApplication#createContext
* @param {Req} req - node native Request object
* @param {Res} res - node native Response object
* @return {Context} context object
Expand Down
4 changes: 2 additions & 2 deletions test/app/extend/context.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -293,8 +293,8 @@ describe('test/app/extend/context.test.js', () => {
.get('/error')
.expect(200)
.expect('hello error');
assert(errorHadEmit);
await sleep(5000);
assert(errorHadEmit);
const logdir = app.config.logger.dir;
const log = fs.readFileSync(path.join(logdir, 'common-error.log'), 'utf8');
assert(/ENOENT: no such file or directory/.test(log));
Expand Down Expand Up @@ -359,8 +359,8 @@ describe('test/app/extend/context.test.js', () => {
.get('/error')
.expect(200)
.expect('hello error');
assert(errorHadEmit);
await sleep(5000);
assert(errorHadEmit);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里顺便修复下 CI 不稳定的问题

const logdir = app.config.logger.dir;
const log = fs.readFileSync(path.join(logdir, 'common-error.log'), 'utf8');
assert(/ENOENT: no such file or directory/.test(log));
Expand Down
3 changes: 3 additions & 0 deletions test/fixtures/apps/httpclient-retry/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "httpclient-retry"
}
27 changes: 27 additions & 0 deletions test/lib/core/httpclient.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -417,4 +417,31 @@ describe('test/lib/core/httpclient.test.js', () => {
assert(!mockApp.config.httpclient.httpsAgent.freeSocketKeepAliveTimeout);
});
});

describe('httpclient retry', () => {
let app;
before(() => {
app = utils.app('apps/httpclient-retry');
return app.ready();
});
after(() => app.close());

it('should retry when httpclient fail', async () => {
let hasRetry = false;
const res = await app.httpclient.curl(`${url}/retry`, {
retry: 1,
retryDelay: 100,
isRetry(res) {
const shouldRetry = res.status >= 500;
if (shouldRetry) {
hasRetry = true;
}
return shouldRetry;
},
});

assert(hasRetry);
assert(res.status === 200);
});
});
});
11 changes: 11 additions & 0 deletions test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ exports.startLocalServer = () => {
if (localServer) {
return resolve('http://127.0.0.1:' + localServer.address().port);
}
let retry = false;
localServer = http.createServer((req, res) => {
req.resume();
req.on('end', () => {
Expand All @@ -62,6 +63,16 @@ exports.startLocalServer = () => {
res.end(`${req.method} ${req.url}`);
}, 10000);
return;
} else if (req.url === '/retry') {
if (!retry) {
retry = true;
res.statusCode = 500;
res.end();
} else {
res.statusCode = 200;
res.end('retry suc');
}
return;
} else {
res.end(`${req.method} ${req.url}`);
}
Expand Down