Skip to content

Commit 3438777

Browse files
authored
fix(otlp-grpc-exporter-base): avoid TypeError on exporter shutdown (#4612)
* fix(otlp-grpc-exporter-base): avoid TypeError on exporter shutdown * chore: update changelog * fix: use gRPC Client type over any * fixup! fix: use gRPC Client type over any * fix: use ts-lint/ts-ignore
1 parent b067aed commit 3438777

File tree

3 files changed

+40
-19
lines changed

3 files changed

+40
-19
lines changed

experimental/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ All notable changes to experimental packages in this project will be documented
1919

2020
### :bug: (Bug Fix)
2121

22+
* fix(otlp-grpc-exporter-base): avoid TypeError on exporter shutdown [#4612](https://github.com/open-telemetry/opentelemetry-js/pull/4612)
23+
2224
### :books: (Refine Doc)
2325

2426
### :house: (Internal)

experimental/packages/otlp-grpc-exporter-base/src/grpc-exporter-transport.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@
1616

1717
// NOTE: do not change these type imports to actual imports. Doing so WILL break `@opentelemetry/instrumentation-http`,
1818
// as they'd be imported before the http/https modules can be wrapped.
19-
import type { Metadata, ServiceError, ChannelCredentials } from '@grpc/grpc-js';
19+
import type {
20+
Metadata,
21+
ServiceError,
22+
ChannelCredentials,
23+
Client,
24+
} from '@grpc/grpc-js';
2025
import { ExportResponse } from './export-response';
2126
import { IExporterTransport } from './exporter-transport';
2227

@@ -85,13 +90,13 @@ export interface GrpcExporterTransportParameters {
8590
}
8691

8792
export class GrpcExporterTransport implements IExporterTransport {
88-
private _client?: any;
93+
private _client?: Client;
8994
private _metadata?: Metadata;
9095

9196
constructor(private _parameters: GrpcExporterTransportParameters) {}
9297

9398
shutdown() {
94-
this._client?.shutdown();
99+
this._client?.close();
95100
}
96101

97102
send(data: Uint8Array): Promise<ExportResponse> {
@@ -150,6 +155,8 @@ export class GrpcExporterTransport implements IExporterTransport {
150155
});
151156
}
152157

158+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
159+
// @ts-ignore The gRPC client constructor is created on runtime, so we don't have any types for the resulting client.
153160
this._client.export(
154161
buffer,
155162
this._metadata,

experimental/packages/otlp-grpc-exporter-base/test/grpc-exporter-transport.test.ts

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -136,37 +136,49 @@ describe('GrpcExporterTransport', function () {
136136
});
137137
});
138138
describe('shutdown', function () {
139+
let shutdownHandle: () => void | undefined;
140+
const serverTestContext: ServerTestContext = {
141+
requests: [],
142+
serverResponseProvider: () => {
143+
return { error: null, buffer: Buffer.from([]) };
144+
},
145+
};
146+
147+
beforeEach(async function () {
148+
shutdownHandle = await startServer(serverTestContext);
149+
});
150+
139151
afterEach(function () {
152+
shutdownHandle();
153+
154+
// clear context
155+
serverTestContext.requests = [];
156+
serverTestContext.serverResponseProvider = () => {
157+
return { error: null, buffer: Buffer.from([]) };
158+
};
159+
140160
sinon.restore();
141161
});
162+
142163
it('before send() does not error', function () {
143164
const transport = new GrpcExporterTransport(simpleClientConfig);
144165
transport.shutdown();
145166

146167
// no assertions, just checking that it does not throw any errors.
147168
});
148169

149-
it('calls client shutdown if client is defined', function () {
150-
// arrange
151-
const transport = new GrpcExporterTransport({
152-
metadata: createEmptyMetadata,
153-
timeoutMillis: 100,
154-
grpcPath: 'path',
155-
grpcName: 'name',
156-
credentials: createInsecureCredentials,
157-
compression: 'gzip',
158-
address: 'localhost:1234',
159-
});
160-
const shutdownStub = sinon.stub();
161-
transport['_client'] = {
162-
shutdown: shutdownStub,
163-
};
170+
it('calls _client.close() if client is defined', async function () {
171+
const transport = new GrpcExporterTransport(simpleClientConfig);
172+
// send something so that client is defined
173+
await transport.send(Buffer.from([1, 2, 3]));
174+
assert.ok(transport['_client'], '_client is not defined after send()');
175+
const closeSpy = sinon.spy(transport['_client'], 'close');
164176

165177
// act
166178
transport.shutdown();
167179

168180
// assert
169-
sinon.assert.calledOnce(shutdownStub);
181+
sinon.assert.calledOnce(closeSpy);
170182
});
171183
});
172184
describe('send', function () {

0 commit comments

Comments
 (0)