mirror of https://github.com/grpc/grpc-node.git
				
				
				
			Merge pull request #2750 from murgatroid99/grpc-js_idle_uds_fix
grpc-js: Fix UDS channels not reconnecting after going idle
This commit is contained in:
		
						commit
						45e5fe5462
					
				| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
{
 | 
			
		||||
  "name": "@grpc/grpc-js",
 | 
			
		||||
  "version": "1.10.7",
 | 
			
		||||
  "version": "1.10.8",
 | 
			
		||||
  "description": "gRPC Library for Node - pure JS implementation",
 | 
			
		||||
  "homepage": "https://grpc.io/",
 | 
			
		||||
  "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,7 +50,7 @@ class UdsResolver implements Resolver {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  destroy() {
 | 
			
		||||
    // This resolver owns no resources, so we do nothing here.
 | 
			
		||||
    this.hasReturnedResult = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static getDefaultAuthority(target: GrpcUri): string {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,8 @@ import * as loader from '@grpc/proto-loader';
 | 
			
		|||
import * as assert2 from './assert2';
 | 
			
		||||
import * as path from 'path';
 | 
			
		||||
import * as grpc from '../src';
 | 
			
		||||
import * as fsPromises from 'fs/promises';
 | 
			
		||||
import * as os from 'os';
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  GrpcObject,
 | 
			
		||||
| 
						 | 
				
			
			@ -71,54 +73,77 @@ const serviceImpl = {
 | 
			
		|||
 | 
			
		||||
export class TestServer {
 | 
			
		||||
  private server: grpc.Server;
 | 
			
		||||
  public port: number | null = null;
 | 
			
		||||
  private target: string | null = null;
 | 
			
		||||
  constructor(public useTls: boolean, options?: grpc.ServerOptions) {
 | 
			
		||||
    this.server = new grpc.Server(options);
 | 
			
		||||
    this.server.addService(echoService.service, serviceImpl);
 | 
			
		||||
  }
 | 
			
		||||
  start(): Promise<void> {
 | 
			
		||||
    let credentials: grpc.ServerCredentials;
 | 
			
		||||
 | 
			
		||||
  private getCredentials(): grpc.ServerCredentials {
 | 
			
		||||
    if (this.useTls) {
 | 
			
		||||
      credentials = grpc.ServerCredentials.createSsl(null, [
 | 
			
		||||
      return grpc.ServerCredentials.createSsl(null, [
 | 
			
		||||
        { private_key: key, cert_chain: cert },
 | 
			
		||||
      ]);
 | 
			
		||||
    } else {
 | 
			
		||||
      credentials = grpc.ServerCredentials.createInsecure();
 | 
			
		||||
      return grpc.ServerCredentials.createInsecure();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  start(): Promise<void> {
 | 
			
		||||
    return new Promise<void>((resolve, reject) => {
 | 
			
		||||
      this.server.bindAsync('localhost:0', credentials, (error, port) => {
 | 
			
		||||
      this.server.bindAsync('localhost:0', this.getCredentials(), (error, port) => {
 | 
			
		||||
        if (error) {
 | 
			
		||||
          reject(error);
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        this.port = port;
 | 
			
		||||
        this.target = `localhost:${port}`;
 | 
			
		||||
        resolve();
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  startUds(): Promise<void> {
 | 
			
		||||
    return fsPromises.mkdtemp(path.join(os.tmpdir(), 'uds')).then(dir => {
 | 
			
		||||
      return new Promise<void>((resolve, reject) => {
 | 
			
		||||
        const target = `unix://${dir}/socket`;
 | 
			
		||||
        this.server.bindAsync(target, this.getCredentials(), (error, port) => {
 | 
			
		||||
          if (error) {
 | 
			
		||||
            reject(error);
 | 
			
		||||
            return;
 | 
			
		||||
          }
 | 
			
		||||
          this.target = target;
 | 
			
		||||
          resolve();
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  shutdown() {
 | 
			
		||||
    this.server.forceShutdown();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getTarget() {
 | 
			
		||||
    if (this.target === null) {
 | 
			
		||||
      throw new Error('Server not yet started');
 | 
			
		||||
    }
 | 
			
		||||
    return this.target;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class TestClient {
 | 
			
		||||
  private client: ServiceClient;
 | 
			
		||||
  constructor(port: number, useTls: boolean, options?: grpc.ChannelOptions) {
 | 
			
		||||
  constructor(target: string, useTls: boolean, options?: grpc.ChannelOptions) {
 | 
			
		||||
    let credentials: grpc.ChannelCredentials;
 | 
			
		||||
    if (useTls) {
 | 
			
		||||
      credentials = grpc.credentials.createSsl(ca);
 | 
			
		||||
    } else {
 | 
			
		||||
      credentials = grpc.credentials.createInsecure();
 | 
			
		||||
    }
 | 
			
		||||
    this.client = new echoService(`localhost:${port}`, credentials, options);
 | 
			
		||||
    this.client = new echoService(target, credentials, options);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static createFromServer(server: TestServer, options?: grpc.ChannelOptions) {
 | 
			
		||||
    if (server.port === null) {
 | 
			
		||||
      throw new Error('Cannot create client, server not started');
 | 
			
		||||
    }
 | 
			
		||||
    return new TestClient(server.port, server.useTls, options);
 | 
			
		||||
    return new TestClient(server.getTarget(), server.useTls, options);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  waitForReady(deadline: grpc.Deadline, callback: (error?: Error) => void) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -129,6 +129,47 @@ describe('Channel idle timer', () => {
 | 
			
		|||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
describe('Channel idle timer with UDS', () => {
 | 
			
		||||
  let server: TestServer;
 | 
			
		||||
  let client: TestClient | null = null;
 | 
			
		||||
  before(() => {
 | 
			
		||||
    server = new TestServer(false);
 | 
			
		||||
    return server.startUds();
 | 
			
		||||
  });
 | 
			
		||||
  afterEach(() => {
 | 
			
		||||
    if (client) {
 | 
			
		||||
      client.close();
 | 
			
		||||
      client = null;
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
  after(() => {
 | 
			
		||||
    server.shutdown();
 | 
			
		||||
  });
 | 
			
		||||
  it('Should be able to make a request after going idle', function (done) {
 | 
			
		||||
    this.timeout(5000);
 | 
			
		||||
    client = TestClient.createFromServer(server, {
 | 
			
		||||
      'grpc.client_idle_timeout_ms': 1000,
 | 
			
		||||
    });
 | 
			
		||||
    client.sendRequest(error => {
 | 
			
		||||
      assert.ifError(error);
 | 
			
		||||
      assert.strictEqual(
 | 
			
		||||
        client!.getChannelState(),
 | 
			
		||||
        grpc.connectivityState.READY
 | 
			
		||||
      );
 | 
			
		||||
      setTimeout(() => {
 | 
			
		||||
        assert.strictEqual(
 | 
			
		||||
          client!.getChannelState(),
 | 
			
		||||
          grpc.connectivityState.IDLE
 | 
			
		||||
        );
 | 
			
		||||
        client!.sendRequest(error => {
 | 
			
		||||
          assert.ifError(error);
 | 
			
		||||
          done();
 | 
			
		||||
        });
 | 
			
		||||
      }, 1100);
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
describe('Server idle timer', () => {
 | 
			
		||||
  let server: TestServer;
 | 
			
		||||
  let client: TestClient | null = null;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -811,7 +811,7 @@ describe('pick_first load balancing policy', () => {
 | 
			
		|||
      before(async () => {
 | 
			
		||||
        server = new TestServer(false);
 | 
			
		||||
        await server.start();
 | 
			
		||||
        client = new TestClient(server.port!, false, {
 | 
			
		||||
        client = TestClient.createFromServer(server, {
 | 
			
		||||
          'grpc.service_config': JSON.stringify(serviceConfig),
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -153,7 +153,7 @@ describe('Server interceptors', () => {
 | 
			
		|||
        grpc.ServerCredentials.createInsecure(),
 | 
			
		||||
        (error, port) => {
 | 
			
		||||
          assert.ifError(error);
 | 
			
		||||
          client = new TestClient(port, false);
 | 
			
		||||
          client = new TestClient(`localhost:${port}`, false);
 | 
			
		||||
          done();
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
| 
						 | 
				
			
			@ -195,7 +195,7 @@ describe('Server interceptors', () => {
 | 
			
		|||
        grpc.ServerCredentials.createInsecure(),
 | 
			
		||||
        (error, port) => {
 | 
			
		||||
          assert.ifError(error);
 | 
			
		||||
          client = new TestClient(port, false);
 | 
			
		||||
          client = new TestClient(`localhost:${port}`, false);
 | 
			
		||||
          done();
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
| 
						 | 
				
			
			@ -246,7 +246,7 @@ describe('Server interceptors', () => {
 | 
			
		|||
        grpc.ServerCredentials.createInsecure(),
 | 
			
		||||
        (error, port) => {
 | 
			
		||||
          assert.ifError(error);
 | 
			
		||||
          client = new TestClient(port, false);
 | 
			
		||||
          client = new TestClient(`localhost:${port}`, false);
 | 
			
		||||
          done();
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
| 
						 | 
				
			
			@ -292,7 +292,7 @@ describe('Server interceptors', () => {
 | 
			
		|||
        grpc.ServerCredentials.createInsecure(),
 | 
			
		||||
        (error, port) => {
 | 
			
		||||
          assert.ifError(error);
 | 
			
		||||
          client = new TestClient(port, false);
 | 
			
		||||
          client = new TestClient(`localhost:${port}`, false);
 | 
			
		||||
          done();
 | 
			
		||||
        }
 | 
			
		||||
      );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue