Skip to content

Commit 4bce38b

Browse files
authored
fix: ETIMEDOUT error with Bluebird when connecting. (#925)
There's a race condition when making connections in 4.11.x, which will happen easier with Bluebird & Unix socks. Thank you to @jeremytm & @p3x-robot. Close #918
1 parent a90f0de commit 4bce38b

File tree

3 files changed

+43
-27
lines changed

3 files changed

+43
-27
lines changed

lib/connectors/SentinelConnector/index.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import SentinelIterator from "./SentinelIterator";
1515
import { ISentinelAddress } from "./types";
1616
import AbstractConnector, { ErrorEmitter } from "../AbstractConnector";
1717
import { NetStream, CallbackFunction } from "../../types";
18-
import * as PromiseContainer from "../../promiseContainer";
1918
import Redis from "../../redis";
2019

2120
const debug = Debug("SentinelConnector");
@@ -87,10 +86,9 @@ export default class SentinelConnector extends AbstractConnector {
8786
this.retryAttempts = 0;
8887

8988
let lastError;
90-
const _Promise = PromiseContainer.get();
9189

9290
const connectToNext = () =>
93-
new _Promise<NetStream>((resolve, reject) => {
91+
new Promise<NetStream>((resolve, reject) => {
9492
const endpoint = this.sentinelIterator.next();
9593

9694
if (endpoint.done) {

lib/connectors/StandaloneConnector.ts

+22-19
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import { createConnection, TcpNetConnectOpts, IpcNetConnectOpts } from "net";
22
import { connect as createTLSConnection, SecureContextOptions } from "tls";
33
import { CONNECTION_CLOSED_ERROR_MSG } from "../utils";
44
import AbstractConnector, { ErrorEmitter } from "./AbstractConnector";
5-
import * as PromiseContainer from "../promiseContainer";
65
import { NetStream } from "../types";
76

87
export function isIIpcConnectionOptions(
@@ -52,27 +51,31 @@ export default class StandaloneConnector extends AbstractConnector {
5251
Object.assign(connectionOptions, options.tls);
5352
}
5453

55-
const _Promise = PromiseContainer.get();
56-
return new _Promise<NetStream>((resolve, reject) => {
57-
process.nextTick(() => {
58-
if (!this.connecting) {
59-
reject(new Error(CONNECTION_CLOSED_ERROR_MSG));
60-
return;
61-
}
54+
// TODO:
55+
// We use native Promise here since other Promise
56+
// implementation may use different schedulers that
57+
// cause issue when the stream is resolved in the
58+
// next tick.
59+
// Should use the provided promise in the next major
60+
// version and do not connect before resolved.
61+
return new Promise<NetStream>((resolve, reject) => {
62+
if (!this.connecting) {
63+
reject(new Error(CONNECTION_CLOSED_ERROR_MSG));
64+
return;
65+
}
6266

63-
try {
64-
if (options.tls) {
65-
this.stream = createTLSConnection(connectionOptions);
66-
} else {
67-
this.stream = createConnection(connectionOptions);
68-
}
69-
} catch (err) {
70-
reject(err);
71-
return;
67+
try {
68+
if (options.tls) {
69+
this.stream = createTLSConnection(connectionOptions);
70+
} else {
71+
this.stream = createConnection(connectionOptions);
7272
}
73+
} catch (err) {
74+
reject(err);
75+
return;
76+
}
7377

74-
resolve(this.stream);
75-
});
78+
resolve(this.stream);
7679
});
7780
}
7881
}

test/functional/connection.ts

+20-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { Socket } from "net";
1+
import * as net from "net";
22
import Redis from "../../lib/redis";
33
import * as sinon from "sinon";
44
import { expect } from "chai";
55
import MockServer from "../helpers/mock_server";
6+
import * as Bluebird from "bluebird";
67

78
describe("connection", function() {
89
it('should emit "connect" when connected', function(done) {
@@ -77,9 +78,9 @@ describe("connection", function() {
7778
var set = false;
7879

7980
// TODO: use spy
80-
// @ts-ignore
8181
const stub = sinon
82-
.stub(Socket.prototype, "setTimeout")
82+
.stub(net.Socket.prototype, "setTimeout")
83+
// @ts-ignore
8384
.callsFake(timeout => {
8485
if (timeout === connectTimeout) {
8586
set = true;
@@ -103,9 +104,9 @@ describe("connection", function() {
103104
let timedoutCalled = false;
104105

105106
// TODO: use spy
106-
// @ts-ignore
107107
sinon
108-
.stub(Socket.prototype, "setTimeout")
108+
.stub(net.Socket.prototype, "setTimeout")
109+
// @ts-ignore
109110
.callsFake((timeout, callback) => {
110111
if (timeout === 0) {
111112
if (!isReady) {
@@ -383,4 +384,18 @@ describe("connection", function() {
383384
});
384385
});
385386
});
387+
388+
describe("sync connection", () => {
389+
it("works with synchronous connection", done => {
390+
// @ts-ignore
391+
Redis.Promise = Bluebird;
392+
const redis = new Redis("/data");
393+
redis.on("error", () => {
394+
// @ts-ignore
395+
Redis.Promise = Promise;
396+
redis.disconnect();
397+
done();
398+
});
399+
});
400+
});
386401
});

0 commit comments

Comments
 (0)