Fix race between destroying call after status and handling write failure

pull/11141/head
murgatroid99 8 years ago
parent c80d3321d0
commit 8d18c6edfb
  1. 8
      src/node/ext/call.cc
  2. 12
      src/node/src/client.js

@ -721,6 +721,14 @@ NAN_METHOD(Call::StartBatch) {
}
Local<Function> callback_func = info[1].As<Function>();
Call *call = ObjectWrap::Unwrap<Call>(info.This());
if (call->wrapped_call == NULL) {
/* This implies that the call has completed and has been destroyed. To emulate
* previous behavior, we should call the callback immediately with an error,
* as though the batch had failed in core */
Local<Value> argv[] = {Nan::Error("The async function failed because the call has completed")};
Nan::Call(callback_func, Nan::New<Object>(), 1, argv);
return;
}
Local<Object> obj = Nan::To<Object>(info[0]).ToLocalChecked();
Local<Array> keys = Nan::GetOwnPropertyNames(obj).ToLocalChecked();
size_t nops = keys->Length();

@ -100,6 +100,12 @@ function _write(chunk, encoding, callback) {
/* jshint validthis: true */
var batch = {};
var message;
var self = this;
if (this.writeFailed) {
/* Once a write fails, just call the callback immediately to let the caller
flush any pending writes. */
callback();
}
try {
message = this.serialize(chunk);
} catch (e) {
@ -119,8 +125,10 @@ function _write(chunk, encoding, callback) {
batch[grpc.opType.SEND_MESSAGE] = message;
this.call.startBatch(batch, function(err, event) {
if (err) {
// Something has gone wrong. Stop writing by failing to call callback
return;
/* Assume that the call is complete and that writing failed because a
status was received. In that case, set a flag to discard all future
writes */
self.writeFailed = true;
}
callback();
});

Loading…
Cancel
Save