grpc-js: Idle timeout: format files

This commit is contained in:
Michael Lumish 2023-06-20 15:46:27 -07:00
parent fcff72b941
commit 89cd8f7bc3
4 changed files with 84 additions and 29 deletions

View File

@ -90,7 +90,7 @@ export const recognizedOptions = {
'grpc.max_connection_age_grace_ms': true,
'grpc-node.max_session_memory': true,
'grpc.service_config_disable_resolution': true,
'grpc.client_idle_timeout_ms': true
'grpc.client_idle_timeout_ms': true,
};
export function channelOptionsEqual(

View File

@ -20,7 +20,12 @@ import { ChannelOptions } from './channel-options';
import { ResolvingLoadBalancer } from './resolving-load-balancer';
import { SubchannelPool, getSubchannelPool } from './subchannel-pool';
import { ChannelControlHelper } from './load-balancer';
import { UnavailablePicker, Picker, PickResultType, QueuePicker } from './picker';
import {
UnavailablePicker,
Picker,
PickResultType,
QueuePicker,
} from './picker';
import { Metadata } from './metadata';
import { Status, LogVerbosity, Propagate } from './constants';
import { FilterStackFactory } from './filter-stack';
@ -191,9 +196,10 @@ export class InternalChannel {
private currentResolutionError: StatusObject | null = null;
private readonly retryBufferTracker: MessageBufferTracker;
private keepaliveTime: number;
private readonly wrappedSubchannels: Set<ChannelSubchannelWrapper> = new Set();
private readonly wrappedSubchannels: Set<ChannelSubchannelWrapper> =
new Set();
private callCount: number = 0;
private callCount = 0;
private idleTimer: NodeJS.Timer | null = null;
private readonly idleTimeoutMs: number;
@ -274,7 +280,10 @@ export class InternalChannel {
DEFAULT_PER_RPC_RETRY_BUFFER_SIZE_BYTES
);
this.keepaliveTime = options['grpc.keepalive_time_ms'] ?? -1;
this.idleTimeoutMs = Math.max(options['grpc.client_idle_timeout_ms'] ?? DEFAULT_IDLE_TIMEOUT_MS, MIN_IDLE_TIMEOUT_MS);
this.idleTimeoutMs = Math.max(
options['grpc.client_idle_timeout_ms'] ?? DEFAULT_IDLE_TIMEOUT_MS,
MIN_IDLE_TIMEOUT_MS
);
const channelControlHelper: ChannelControlHelper = {
createSubchannel: (
subchannelAddress: SubchannelAddress,
@ -567,7 +576,11 @@ export class InternalChannel {
private maybeStartIdleTimer() {
if (this.callCount === 0) {
this.idleTimer = setTimeout(() => {
this.trace('Idle timer triggered after ' + this.idleTimeoutMs + 'ms of inactivity');
this.trace(
'Idle timer triggered after ' +
this.idleTimeoutMs +
'ms of inactivity'
);
this.enterIdle();
}, this.idleTimeoutMs);
this.idleTimer.unref?.();

View File

@ -20,7 +20,12 @@ import * as assert2 from './assert2';
import * as path from 'path';
import * as grpc from '../src';
import { GrpcObject, ServiceClientConstructor, ServiceClient, loadPackageDefinition } from '../src/make-client';
import {
GrpcObject,
ServiceClientConstructor,
ServiceClient,
loadPackageDefinition,
} from '../src/make-client';
import { readFileSync } from 'fs';
const protoLoaderOptions = {
@ -67,7 +72,9 @@ export class TestServer {
start(): Promise<void> {
let credentials: grpc.ServerCredentials;
if (this.useTls) {
credentials = grpc.ServerCredentials.createSsl(null, [{private_key: key, cert_chain: cert}]);
credentials = grpc.ServerCredentials.createSsl(null, [
{ private_key: key, cert_chain: cert },
]);
} else {
credentials = grpc.ServerCredentials.createInsecure();
}

View File

@ -17,7 +17,7 @@
import * as assert from 'assert';
import * as grpc from '../src';
import { TestClient, TestServer } from "./common";
import { TestClient, TestServer } from './common';
describe('Channel idle timer', () => {
let server: TestServer;
@ -31,30 +31,46 @@ describe('Channel idle timer', () => {
client.close();
client = null;
}
})
});
after(() => {
server.shutdown();
});
it('Should go idle after the specified time after a request ends', function(done) {
it('Should go idle after the specified time after a request ends', function (done) {
this.timeout(5000);
client = TestClient.createFromServer(server, {'grpc.client_idle_timeout_ms': 1000});
client = TestClient.createFromServer(server, {
'grpc.client_idle_timeout_ms': 1000,
});
client.sendRequest(error => {
assert.ifError(error);
assert.strictEqual(client!.getChannelState(), grpc.connectivityState.READY);
assert.strictEqual(
client!.getChannelState(),
grpc.connectivityState.READY
);
setTimeout(() => {
assert.strictEqual(client!.getChannelState(), grpc.connectivityState.IDLE);
assert.strictEqual(
client!.getChannelState(),
grpc.connectivityState.IDLE
);
done();
}, 1100);
});
});
it('Should be able to make a request after going idle', function(done) {
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 = TestClient.createFromServer(server, {
'grpc.client_idle_timeout_ms': 1000,
});
client.sendRequest(error => {
assert.ifError(error);
assert.strictEqual(client!.getChannelState(), grpc.connectivityState.READY);
assert.strictEqual(
client!.getChannelState(),
grpc.connectivityState.READY
);
setTimeout(() => {
assert.strictEqual(client!.getChannelState(), grpc.connectivityState.IDLE);
assert.strictEqual(
client!.getChannelState(),
grpc.connectivityState.IDLE
);
client!.sendRequest(error => {
assert.ifError(error);
done();
@ -62,34 +78,53 @@ describe('Channel idle timer', () => {
}, 1100);
});
});
it('Should go idle after the specified time after waitForReady ends', function(done) {
it('Should go idle after the specified time after waitForReady ends', function (done) {
this.timeout(5000);
client = TestClient.createFromServer(server, {'grpc.client_idle_timeout_ms': 1000});
client = TestClient.createFromServer(server, {
'grpc.client_idle_timeout_ms': 1000,
});
const deadline = new Date();
deadline.setSeconds(deadline.getSeconds() + 3);
client.waitForReady(deadline, error => {
assert.ifError(error);
assert.strictEqual(client!.getChannelState(), grpc.connectivityState.READY);
assert.strictEqual(
client!.getChannelState(),
grpc.connectivityState.READY
);
setTimeout(() => {
assert.strictEqual(client!.getChannelState(), grpc.connectivityState.IDLE);
assert.strictEqual(
client!.getChannelState(),
grpc.connectivityState.IDLE
);
done();
}, 1100);
});
});
it('Should ensure that the timeout is at least 1 second', function(done) {
client = TestClient.createFromServer(server, {'grpc.client_idle_timeout_ms': 50});
it('Should ensure that the timeout is at least 1 second', function (done) {
client = TestClient.createFromServer(server, {
'grpc.client_idle_timeout_ms': 50,
});
client.sendRequest(error => {
assert.ifError(error);
assert.strictEqual(client!.getChannelState(), grpc.connectivityState.READY);
assert.strictEqual(
client!.getChannelState(),
grpc.connectivityState.READY
);
setTimeout(() => {
// Should still be ready after 100ms
assert.strictEqual(client!.getChannelState(), grpc.connectivityState.READY);
assert.strictEqual(
client!.getChannelState(),
grpc.connectivityState.READY
);
setTimeout(() => {
// Should go IDLE after another second
assert.strictEqual(client!.getChannelState(), grpc.connectivityState.IDLE);
assert.strictEqual(
client!.getChannelState(),
grpc.connectivityState.IDLE
);
done();
}, 1000);
}, 100);
});
})
});
});
});