Skip to content

Commit 45e5fe5

Browse files
authored
Merge pull request #2750 from murgatroid99/grpc-js_idle_uds_fix
grpc-js: Fix UDS channels not reconnecting after going idle
2 parents 3105791 + 87a3541 commit 45e5fe5

File tree

6 files changed

+86
-20
lines changed

6 files changed

+86
-20
lines changed

packages/grpc-js/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@grpc/grpc-js",
3-
"version": "1.10.7",
3+
"version": "1.10.8",
44
"description": "gRPC Library for Node - pure JS implementation",
55
"homepage": "https://grpc.io/",
66
"repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js",

packages/grpc-js/src/resolver-uds.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class UdsResolver implements Resolver {
5050
}
5151

5252
destroy() {
53-
// This resolver owns no resources, so we do nothing here.
53+
this.hasReturnedResult = false;
5454
}
5555

5656
static getDefaultAuthority(target: GrpcUri): string {

packages/grpc-js/test/common.ts

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import * as loader from '@grpc/proto-loader';
1919
import * as assert2 from './assert2';
2020
import * as path from 'path';
2121
import * as grpc from '../src';
22+
import * as fsPromises from 'fs/promises';
23+
import * as os from 'os';
2224

2325
import {
2426
GrpcObject,
@@ -71,54 +73,77 @@ const serviceImpl = {
7173

7274
export class TestServer {
7375
private server: grpc.Server;
74-
public port: number | null = null;
76+
private target: string | null = null;
7577
constructor(public useTls: boolean, options?: grpc.ServerOptions) {
7678
this.server = new grpc.Server(options);
7779
this.server.addService(echoService.service, serviceImpl);
7880
}
79-
start(): Promise<void> {
80-
let credentials: grpc.ServerCredentials;
81+
82+
private getCredentials(): grpc.ServerCredentials {
8183
if (this.useTls) {
82-
credentials = grpc.ServerCredentials.createSsl(null, [
84+
return grpc.ServerCredentials.createSsl(null, [
8385
{ private_key: key, cert_chain: cert },
8486
]);
8587
} else {
86-
credentials = grpc.ServerCredentials.createInsecure();
88+
return grpc.ServerCredentials.createInsecure();
8789
}
90+
}
91+
92+
start(): Promise<void> {
8893
return new Promise<void>((resolve, reject) => {
89-
this.server.bindAsync('localhost:0', credentials, (error, port) => {
94+
this.server.bindAsync('localhost:0', this.getCredentials(), (error, port) => {
9095
if (error) {
9196
reject(error);
9297
return;
9398
}
94-
this.port = port;
99+
this.target = `localhost:${port}`;
95100
resolve();
96101
});
97102
});
98103
}
99104

105+
startUds(): Promise<void> {
106+
return fsPromises.mkdtemp(path.join(os.tmpdir(), 'uds')).then(dir => {
107+
return new Promise<void>((resolve, reject) => {
108+
const target = `unix://${dir}/socket`;
109+
this.server.bindAsync(target, this.getCredentials(), (error, port) => {
110+
if (error) {
111+
reject(error);
112+
return;
113+
}
114+
this.target = target;
115+
resolve();
116+
});
117+
});
118+
});
119+
}
120+
100121
shutdown() {
101122
this.server.forceShutdown();
102123
}
124+
125+
getTarget() {
126+
if (this.target === null) {
127+
throw new Error('Server not yet started');
128+
}
129+
return this.target;
130+
}
103131
}
104132

105133
export class TestClient {
106134
private client: ServiceClient;
107-
constructor(port: number, useTls: boolean, options?: grpc.ChannelOptions) {
135+
constructor(target: string, useTls: boolean, options?: grpc.ChannelOptions) {
108136
let credentials: grpc.ChannelCredentials;
109137
if (useTls) {
110138
credentials = grpc.credentials.createSsl(ca);
111139
} else {
112140
credentials = grpc.credentials.createInsecure();
113141
}
114-
this.client = new echoService(`localhost:${port}`, credentials, options);
142+
this.client = new echoService(target, credentials, options);
115143
}
116144

117145
static createFromServer(server: TestServer, options?: grpc.ChannelOptions) {
118-
if (server.port === null) {
119-
throw new Error('Cannot create client, server not started');
120-
}
121-
return new TestClient(server.port, server.useTls, options);
146+
return new TestClient(server.getTarget(), server.useTls, options);
122147
}
123148

124149
waitForReady(deadline: grpc.Deadline, callback: (error?: Error) => void) {

packages/grpc-js/test/test-idle-timer.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,47 @@ describe('Channel idle timer', () => {
129129
});
130130
});
131131

132+
describe('Channel idle timer with UDS', () => {
133+
let server: TestServer;
134+
let client: TestClient | null = null;
135+
before(() => {
136+
server = new TestServer(false);
137+
return server.startUds();
138+
});
139+
afterEach(() => {
140+
if (client) {
141+
client.close();
142+
client = null;
143+
}
144+
});
145+
after(() => {
146+
server.shutdown();
147+
});
148+
it('Should be able to make a request after going idle', function (done) {
149+
this.timeout(5000);
150+
client = TestClient.createFromServer(server, {
151+
'grpc.client_idle_timeout_ms': 1000,
152+
});
153+
client.sendRequest(error => {
154+
assert.ifError(error);
155+
assert.strictEqual(
156+
client!.getChannelState(),
157+
grpc.connectivityState.READY
158+
);
159+
setTimeout(() => {
160+
assert.strictEqual(
161+
client!.getChannelState(),
162+
grpc.connectivityState.IDLE
163+
);
164+
client!.sendRequest(error => {
165+
assert.ifError(error);
166+
done();
167+
});
168+
}, 1100);
169+
});
170+
});
171+
});
172+
132173
describe('Server idle timer', () => {
133174
let server: TestServer;
134175
let client: TestClient | null = null;

packages/grpc-js/test/test-pick-first.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -811,7 +811,7 @@ describe('pick_first load balancing policy', () => {
811811
before(async () => {
812812
server = new TestServer(false);
813813
await server.start();
814-
client = new TestClient(server.port!, false, {
814+
client = TestClient.createFromServer(server, {
815815
'grpc.service_config': JSON.stringify(serviceConfig),
816816
});
817817
});

packages/grpc-js/test/test-server-interceptors.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ describe('Server interceptors', () => {
153153
grpc.ServerCredentials.createInsecure(),
154154
(error, port) => {
155155
assert.ifError(error);
156-
client = new TestClient(port, false);
156+
client = new TestClient(`localhost:${port}`, false);
157157
done();
158158
}
159159
);
@@ -195,7 +195,7 @@ describe('Server interceptors', () => {
195195
grpc.ServerCredentials.createInsecure(),
196196
(error, port) => {
197197
assert.ifError(error);
198-
client = new TestClient(port, false);
198+
client = new TestClient(`localhost:${port}`, false);
199199
done();
200200
}
201201
);
@@ -246,7 +246,7 @@ describe('Server interceptors', () => {
246246
grpc.ServerCredentials.createInsecure(),
247247
(error, port) => {
248248
assert.ifError(error);
249-
client = new TestClient(port, false);
249+
client = new TestClient(`localhost:${port}`, false);
250250
done();
251251
}
252252
);
@@ -292,7 +292,7 @@ describe('Server interceptors', () => {
292292
grpc.ServerCredentials.createInsecure(),
293293
(error, port) => {
294294
assert.ifError(error);
295-
client = new TestClient(port, false);
295+
client = new TestClient(`localhost:${port}`, false);
296296
done();
297297
}
298298
);

0 commit comments

Comments
 (0)