aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Michael Lumish <mlumish@google.com>2017-05-17 17:26:27 -0700
committerGravatar GitHub <noreply@github.com>2017-05-17 17:26:27 -0700
commitc7cde2334ed3c6c2f6b3217d38b294a063ab70e9 (patch)
tree4ee7ac36fe465805656c30a5cac4df0ac267f1e8 /src
parent42d858a99d8b978e75ea48af9d4c556ac53598cc (diff)
parentd822e2f5cf8d32efd0008c967551e994046b2d73 (diff)
Merge pull request #11141 from murgatroid99/node_write_after_end_race_fix
Fix race between destroying call after status and handling write failure
Diffstat (limited to 'src')
-rw-r--r--src/node/ext/call.cc8
-rw-r--r--src/node/src/client.js12
2 files changed, 18 insertions, 2 deletions
diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc
index 8877995f8f..2cc9f63b65 100644
--- a/src/node/ext/call.cc
+++ b/src/node/ext/call.cc
@@ -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();
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 1aaf35c16c..2073d3eea8 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -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. */
+ setImmediate(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();
});