Skip to content

Commit 3ad1228

Browse files
aknuds1marefr
andauthored
Plugin: Migrate to @grpc/grpc-js to resolve problems when IPv6 is disabled (#135)
* Migrate to @grpc/grpc-js * Download grpc no longer needed as part of packaging * Package using node 12 (^8.13.0 || >=10.10.0) required for grpc-js * zeit/pkg upgrade to support node 12 Signed-off-by: Arve Knudsen <[email protected]> Co-authored-by: Marcus Efraimsson <[email protected]>
1 parent d70d1dc commit 3ad1228

File tree

10 files changed

+266
-1368
lines changed

10 files changed

+266
-1368
lines changed

package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
"start": "node build/app.js --config=dev.json"
1919
},
2020
"dependencies": {
21-
"@grpc/proto-loader": "^0.5.3",
21+
"@grpc/grpc-js": "^1.0",
22+
"@grpc/proto-loader": "^0.5.4",
2223
"@hapi/boom": "^8.0.1",
2324
"express": "^4.16.3",
2425
"express-prom-bundle": "^5.1.5",
2526
"google-protobuf": "3.5.0",
26-
"grpc": "^1.24.2",
2727
"lodash": "^4.17.15",
2828
"minimist": "^1.2.0",
2929
"morgan": "^1.9.0",
@@ -39,7 +39,7 @@
3939
"@types/node": "^10.0.9",
4040
"husky": "^3.1.0",
4141
"lint-staged": "^9.5.0",
42-
"pkg": "4.3.8",
42+
"pkg": "4.4.8",
4343
"prettier": "^1.19.1",
4444
"tsc-watch": "^4.2.3",
4545
"tslint": "^6.1.1",
@@ -65,5 +65,8 @@
6565
"bin": "build/app.js",
6666
"engines": {
6767
"node": ">=12 <13"
68+
},
69+
"volta": {
70+
"node": "12.16.2"
6871
}
6972
}

scripts/download_grpc.js

Lines changed: 0 additions & 79 deletions
This file was deleted.

scripts/package_target.sh

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,6 @@ if [ $? != 0 ]; then
2525
echo "${?}\n". 1>&2 && exit 1
2626
fi
2727

28-
node scripts/download_grpc.js ${ARCH} ${OUT}
29-
30-
if [ $? != 0 ]; then
31-
echo "${?}\n". 1>&2 && exit 1
32-
fi
33-
3428
node scripts/rename_executable.js ${ARCH} ${OUT}
3529

3630
if [ $? != 0 ]; then

scripts/pkg.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ platform = platformTransform[platform] || platform;
2424
arch = archTransform[arch] || arch;
2525
const outputPath = "dist/" + (process.argv[3] || `plugin-${archArg}`);
2626

27-
childProcess.execSync(`./node_modules/.bin/pkg -t node10-${platform}-${arch} . --out-path ${outputPath}`, {stdio: 'inherit'});
27+
childProcess.execSync(`./node_modules/.bin/pkg -t node12-${platform}-${arch} . --out-path ${outputPath}`, {stdio: 'inherit'});

src/app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ async function main() {
2929
config.rendering.chromeBin = [path.dirname(process.execPath), ...parts].join(path.sep);
3030
}
3131

32-
serve({
32+
await serve({
3333
handshakeConfig: {
3434
protocolVersion: 2,
3535
magicCookieKey: 'grafana_plugin_type',

src/node-plugin/lib/server.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as grpc from 'grpc';
1+
import * as grpc from '@grpc/grpc-js';
22
import * as protoLoader from '@grpc/proto-loader';
33
import { coreProtocolVersion, PluginSet, VersionedPluginSet, ServeConfig } from './types';
44
import { PluginLogger } from '../../logger';
@@ -81,7 +81,7 @@ const protocolVersion = (opts: ServeConfig): ProtocolNegotiation => {
8181
};
8282
};
8383

84-
export const serve = (opts: ServeConfig) => {
84+
export const serve = async (opts: ServeConfig) => {
8585
const env = Object.assign({}, process.env);
8686
opts.logger = opts.logger || new PluginLogger();
8787

@@ -113,19 +113,26 @@ export const serve = (opts: ServeConfig) => {
113113
for (const key in pluginSet) {
114114
if (pluginSet.hasOwnProperty(key)) {
115115
const p = pluginSet[key];
116-
p.grpcServer(server);
116+
await p.grpcServer(server);
117117
}
118118
}
119119

120120
opts.grpcHost = opts.grpcHost || '127.0.0.1';
121121
opts.grpcPort = opts.grpcPort || 0;
122122

123-
const address = `${opts.grpcHost}:${opts.grpcPort}`;
124-
const boundPortNumber = server.bind(address, grpc.ServerCredentials.createInsecure());
125-
if (boundPortNumber === 0) {
126-
throw new Error(`failed to bind address=${address}, boundPortNumber=${boundPortNumber}`);
127-
}
123+
return new Promise<void>((resolve, reject) => {
124+
const address = `${opts.grpcHost}:${opts.grpcPort}`;
125+
server.bindAsync(address, grpc.ServerCredentials.createInsecure(), (error: Error | null, port: number) => {
126+
if (error) {
127+
reject(error);
128+
}
129+
if (port === 0) {
130+
reject(new Error(`failed to bind address=${address}, boundPortNumber=${port}`));
131+
}
128132

129-
server.start();
130-
console.log(`${coreProtocolVersion}|${protoVersion}|tcp|${opts.grpcHost}:${boundPortNumber}|grpc`);
133+
server.start();
134+
console.log(`${coreProtocolVersion}|${protoVersion}|tcp|${opts.grpcHost}:${port}|grpc`);
135+
resolve();
136+
});
137+
});
131138
};

src/node-plugin/lib/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as grpc from 'grpc';
1+
import * as grpc from '@grpc/grpc-js';
22
import { Logger } from '../../logger';
33

44
export interface GrpcPlugin {

src/plugin/v1/grpc_plugin.ts

Lines changed: 30 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as grpc from 'grpc';
1+
import * as grpc from '@grpc/grpc-js';
22
import * as protoLoader from '@grpc/proto-loader';
33
import { GrpcPlugin } from '../../node-plugin';
44
import { Logger } from '../../logger';
@@ -21,44 +21,34 @@ export class RenderGRPCPluginV1 implements GrpcPlugin {
2121

2222
async grpcServer(server: grpc.Server) {
2323
const serviceDef = rendererProtoDescriptor['models']['Renderer']['service'];
24-
const service = new RendererGRPCServer(this.config, this.log);
25-
server.addService(serviceDef, service);
26-
service.start();
27-
}
28-
}
29-
30-
class RendererGRPCServer {
31-
private browser: Browser;
32-
33-
constructor(config: PluginConfig, private log: Logger) {
34-
this.browser = createBrowser(config.rendering, log);
35-
}
36-
37-
async start() {
38-
await this.browser.start();
39-
}
40-
41-
async render(call, callback) {
42-
const req = call.request;
43-
const options: RenderOptions = {
44-
url: req.url,
45-
width: req.width,
46-
height: req.height,
47-
filePath: req.filePath,
48-
timeout: req.timeout,
49-
renderKey: req.renderKey,
50-
domain: req.domain,
51-
timezone: req.timezone,
52-
encoding: req.encoding,
53-
};
54-
55-
try {
56-
this.log.debug('Render request received', 'url', options.url);
57-
await this.browser.render(options);
58-
callback(null, { error: '' });
59-
} catch (err) {
60-
this.log.error('Render request failed', 'url', options.url, 'error', err.toString());
61-
callback(null, { error: err.toString() });
62-
}
24+
const browser = createBrowser(this.config.rendering, this.log);
25+
server.addService(serviceDef, {
26+
render: (call: grpc.ServerUnaryCall<any, any>, callback) => {
27+
const req = call.request;
28+
const options: RenderOptions = {
29+
url: req.url,
30+
width: req.width,
31+
height: req.height,
32+
filePath: req.filePath,
33+
timeout: req.timeout,
34+
renderKey: req.renderKey,
35+
domain: req.domain,
36+
timezone: req.timezone,
37+
encoding: req.encoding,
38+
};
39+
40+
this.log.debug('Render request received', 'url', options.url);
41+
browser.render(options).then(
42+
() => {
43+
callback(null, { error: '' });
44+
},
45+
err => {
46+
this.log.error('Render request failed', 'url', options.url, 'error', err.toString());
47+
callback(null, { error: err.toString() });
48+
}
49+
);
50+
},
51+
});
52+
await browser.start();
6353
}
6454
}

src/plugin/v2/grpc_plugin.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as grpc from 'grpc';
1+
import * as grpc from '@grpc/grpc-js';
22
import * as protoLoader from '@grpc/proto-loader';
33
import * as promClient from 'prom-client';
44
import { GrpcPlugin } from '../../node-plugin';
@@ -45,10 +45,10 @@ export class RenderGRPCPluginV2 implements GrpcPlugin {
4545
const pluginService = new PluginGRPCServer(browser, this.log);
4646

4747
const rendererServiceDef = rendererV2ProtoDescriptor['pluginextensionv2']['Renderer']['service'];
48-
server.addService(rendererServiceDef, pluginService);
48+
server.addService(rendererServiceDef, pluginService as any);
4949

5050
const pluginServiceDef = pluginV2ProtoDescriptor['pluginv2']['Diagnostics']['service'];
51-
server.addService(pluginServiceDef, pluginService);
51+
server.addService(pluginServiceDef, pluginService as any);
5252

5353
const metrics = setupMetrics();
5454
metrics.up.set(1);
@@ -81,10 +81,14 @@ class PluginGRPCServer {
8181
await this.browser.start();
8282
}
8383

84-
async render(call: grpc.ServerUnaryCall<RenderRequest>, callback: grpc.sendUnaryData<RenderResponse>) {
84+
async render(call: grpc.ServerUnaryCall<RenderRequest, any>, callback: grpc.sendUnaryData<RenderResponse>) {
8585
const req = call.request;
8686
const headers: HTTPHeaders = {};
8787

88+
if (!req) {
89+
throw new Error('Request cannot be null');
90+
}
91+
8892
if (req.headers) {
8993
for (const key in req.headers) {
9094
if (req.headers.hasOwnProperty(key)) {
@@ -118,7 +122,7 @@ class PluginGRPCServer {
118122
callback(null, { error: errStr });
119123
}
120124

121-
async checkHealth(_: grpc.ServerUnaryCall<CheckHealthRequest>, callback: grpc.sendUnaryData<CheckHealthResponse>) {
125+
async checkHealth(_: grpc.ServerUnaryCall<CheckHealthRequest, any>, callback: grpc.sendUnaryData<CheckHealthResponse>) {
122126
const jsonDetails = Buffer.from(
123127
JSON.stringify({
124128
browserVersion: this.browserVersion,
@@ -128,7 +132,7 @@ class PluginGRPCServer {
128132
callback(null, { status: HealthStatus.OK, message: 'Success', jsonDetails: jsonDetails });
129133
}
130134

131-
async collectMetrics(_: grpc.ServerUnaryCall<CollectMetricsRequest>, callback: grpc.sendUnaryData<CollectMetricsResponse>) {
135+
async collectMetrics(_: grpc.ServerUnaryCall<CollectMetricsRequest, any>, callback: grpc.sendUnaryData<CollectMetricsResponse>) {
132136
const payload = Buffer.from(promClient.register.metrics());
133137
callback(null, { metrics: { prometheus: payload } });
134138
}

0 commit comments

Comments
 (0)