Different server responses from different versions of this package
Dima-crm28423 opened this issue · 2 comments
Problem description
I have such code (with folder struct.):
greet/proto/greet.proto
syntax = "proto3";
package greet;
message GreetRequest {
string first_name = 1;
};
message GreetResponse {
string result = 1;
};
service GreetService {
rpc GreetManyTimes (GreetRequest) returns (stream GreetResponse);
};
greet/server/index.js
const grpc = require('@grpc/grpc-js');
const serviceImpl = require('./service_impl');
const {GreetServiceService} = require('../proto/greet_grpc_pb');
const addr = 'localhost:50051';
function cleanup(server) {
console.log('Cleanup');
if (server) {
server.forceShutdown();
}
};
function main() {
const server = new grpc.Server();
const creds = grpc.ServerCredentials.createInsecure();
process.on('SIGINT', () => {
console.log('Caught interrupt signal');
cleanup(server);
});
server.addService(GreetServiceService, serviceImpl);
server.bindAsync(addr, creds, (err, _) => {
if (err) {
return cleanup(server);
}
server.start();
});
console.log(`Listening on: ${addr}`);
}
main();
greet/server/service_impl.js
const pb = require('../proto/greet_pb');
exports.greetManyTimes = (call, _) => {
console.log('GreetManyTimes was invoked');
const res = new pb.GreetResponse();
for (let i = 0; i < 10; i++) {
res.setResult(`Hello ${call.request.getFirstName()} - number ${i}`);
call.write(res);
}
call.end();
};
greet/client/index.js
const grpc = require('@grpc/grpc-js');
const {GreetServiceClient} = require('../proto/greet_grpc_pb');
const {GreetRequest} = require('../proto/greet_pb');
function doGreetManyTimes(client) {
console.log('doGreetManyTimes was invoked');
const req = new GreetRequest().setFirstName('Bobby');
const call = client.greetManyTimes(req);
call.on('data', (res) => {
console.log(`GreetManyTimes: ${res.getResult()}`)
})
};
function main() {
const creds = grpc.ChannelCredentials.createInsecure();
const client = new GreetServiceClient('localhost:50051', creds);
doGreetManyTimes(client);
};
main();
scripts/gen.ps1
foreach ( $project in $args ) {
# Generate gRPC and Protobuf code for ${PROJECT}/${PROJECT}.proto
# (eg: greet/greet.proto)
./node_modules/.bin/grpc_tools_node_protoc -I $project/proto `
--js_out=import_style=commonjs:$project/proto `
--grpc_out=grpc_js:$project/proto `
$project/proto/$project.proto;
# Generate only Protobuf code for all the other .proto files (if any)
# (eg: calculator/sum.proto)
Get-ChildItem -Filter *.proto -Recurse $project/proto -Exclude $project.proto | ForEach-Object { `
$file = "./$project/proto/" + $_.Name; `
./node_modules/.bin/grpc_tools_node_protoc -I $project/proto `
--js_out=import_style=commonjs:$project/proto `
$file `
}
}
package.json
{
"name": "my-proj",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"pb:gen": "powershell -ExecutionPolicy unrestricted ./scripts/gen.ps1 greet",
"greet:server": "node greet/server/index.js",
"greet:client": "node greet/client/index.js",
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@grpc/grpc-js": "^1.10.6",
"google-protobuf": "^3.21.2"
},
"devDependencies": {
"grpc-tools": "^1.12.4"
}
}
If @grpc/grpc-js version 1.10.6, the result is (the client terminal):
doGreetManyTimes was invoked
GreetManyTimes: Hello Bobby - number 0
GreetManyTimes: Hello Bobby - number 9
GreetManyTimes: Hello Bobby - number 9
GreetManyTimes: Hello Bobby - number 9
GreetManyTimes: Hello Bobby - number 9
GreetManyTimes: Hello Bobby - number 9
GreetManyTimes: Hello Bobby - number 9
GreetManyTimes: Hello Bobby - number 9
GreetManyTimes: Hello Bobby - number 9
GreetManyTimes: Hello Bobby - number 9
If launch this code using the @grpc/grpc-js version 1.9.9, the result is (the client terminal):
doGreetManyTimes was invoked
GreetManyTimes: Hello Bobby - number 0
GreetManyTimes: Hello Bobby - number 1
GreetManyTimes: Hello Bobby - number 2
GreetManyTimes: Hello Bobby - number 3
GreetManyTimes: Hello Bobby - number 4
GreetManyTimes: Hello Bobby - number 5
GreetManyTimes: Hello Bobby - number 6
GreetManyTimes: Hello Bobby - number 7
GreetManyTimes: Hello Bobby - number 8
GreetManyTimes: Hello Bobby - number 9
Reproduction steps
- Copy the code above (Install deps).
- Launch pb:gen script (npm run pb:gen)
- Launch two terminals
- Start the server (npm run greet:server)
- Start the client (npm run greet:client)
- See the results in the client terminal
- Change the package version (from 1.10.6 to 1.9.9)
- Repeat steps 1-6.
Environment
- OS name, version and architecture: Windows 10 Pro , 64-bit operating system
- Node version 18.20.1
- Node installation method NVM
- Package name and version "@grpc/grpc-js": "^1.10.6"
In service_impl.js
, you have a single res
object that you're trying to send as 10 different messages. In each iteration of the loop, you modify that single message. You cannot count on this producing the outcome you want. This only works if each write operation serializes the message before the next loop iteration. This happens to be true in version 1.9.9 for this particular workload, and it happens not to be true in version 1.10.6.
The solution is to move the line const res = new pb.GreetResponse();
into the loop.
thanks