bare-rpc 1.3.7 → 1.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +39 -8
- package/lib/outgoing-request.js +6 -0
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -29,6 +29,9 @@ module.exports = exports = class RPC {
|
|
|
29
29
|
this._frame = -1
|
|
30
30
|
this._draining = []
|
|
31
31
|
|
|
32
|
+
this._closed = false
|
|
33
|
+
this._error = null
|
|
34
|
+
|
|
32
35
|
if (typeof onrequest === 'function') {
|
|
33
36
|
onrequest = onrequest.bind(this)
|
|
34
37
|
} else {
|
|
@@ -101,6 +104,11 @@ module.exports = exports = class RPC {
|
|
|
101
104
|
}
|
|
102
105
|
|
|
103
106
|
_sendRequest(request, data = null) {
|
|
107
|
+
// Once the channel has been torn down there is nowhere left to send the
|
|
108
|
+
// request. Skip registering it so that it never leaks into the maps; the
|
|
109
|
+
// awaiting reply is rejected through `RPCOutgoingRequest.reply()` instead.
|
|
110
|
+
if (this._closed) return
|
|
111
|
+
|
|
104
112
|
this._outgoingRequests.set(request.id, request)
|
|
105
113
|
|
|
106
114
|
this._sendMessage({
|
|
@@ -114,21 +122,33 @@ module.exports = exports = class RPC {
|
|
|
114
122
|
|
|
115
123
|
_createRequestStream(request, isInitiator, opts) {
|
|
116
124
|
if (isInitiator) {
|
|
117
|
-
this._outgoingRequests.set(request.id, request)
|
|
118
|
-
|
|
119
125
|
request._requestStream = new OutgoingStream(this, request, t.REQUEST, opts)
|
|
120
126
|
|
|
127
|
+
// Once the channel has been torn down there is nowhere left to open the
|
|
128
|
+
// stream, so destroy it right away rather than leave it hanging.
|
|
129
|
+
if (this._closed) return request._requestStream.destroy(this._error)
|
|
130
|
+
|
|
131
|
+
this._outgoingRequests.set(request.id, request)
|
|
132
|
+
|
|
121
133
|
request._requestStream.on('close', () => this._gcOutgoingRequest(request))
|
|
122
134
|
} else {
|
|
123
|
-
this._incomingRequests.set(request.id, request)
|
|
124
|
-
|
|
125
135
|
request._requestStream = new IncomingStream(this, request, t.REQUEST, opts)
|
|
126
136
|
|
|
137
|
+
if (this._closed) return request._requestStream.destroy(this._error)
|
|
138
|
+
|
|
139
|
+
this._incomingRequests.set(request.id, request)
|
|
140
|
+
|
|
127
141
|
request._requestStream.on('close', () => this._incomingRequests.delete(request.id))
|
|
128
142
|
}
|
|
129
143
|
}
|
|
130
144
|
|
|
131
145
|
_sendResponse(request, data) {
|
|
146
|
+
// Once the channel has been torn down there is nowhere left to send the
|
|
147
|
+
// response, so drop it rather than encode and write a message that would
|
|
148
|
+
// only be discarded. The reply is fire-and-forget, so there is nothing to
|
|
149
|
+
// settle.
|
|
150
|
+
if (this._closed) return
|
|
151
|
+
|
|
132
152
|
this._sendMessage({
|
|
133
153
|
type: t.RESPONSE,
|
|
134
154
|
id: request.id,
|
|
@@ -140,16 +160,22 @@ module.exports = exports = class RPC {
|
|
|
140
160
|
|
|
141
161
|
_createResponseStream(request, isInitiator, opts) {
|
|
142
162
|
if (isInitiator) {
|
|
143
|
-
this._outgoingResponses.set(request.id, request)
|
|
144
|
-
|
|
145
163
|
request._responseStream = new OutgoingStream(this, request, t.RESPONSE, opts)
|
|
146
164
|
|
|
165
|
+
// Once the channel has been torn down there is nowhere left to open the
|
|
166
|
+
// stream, so destroy it right away rather than leave it hanging.
|
|
167
|
+
if (this._closed) return request._responseStream.destroy(this._error)
|
|
168
|
+
|
|
169
|
+
this._outgoingResponses.set(request.id, request)
|
|
170
|
+
|
|
147
171
|
request._responseStream.on('close', () => this._outgoingResponses.delete(request.id))
|
|
148
172
|
} else {
|
|
149
|
-
this._incomingResponses.set(request.id, request)
|
|
150
|
-
|
|
151
173
|
request._responseStream = new IncomingStream(this, request, t.RESPONSE, opts)
|
|
152
174
|
|
|
175
|
+
if (this._closed) return request._responseStream.destroy(this._error)
|
|
176
|
+
|
|
177
|
+
this._incomingResponses.set(request.id, request)
|
|
178
|
+
|
|
153
179
|
request._responseStream.on('close', () => {
|
|
154
180
|
this._incomingResponses.delete(request.id)
|
|
155
181
|
|
|
@@ -192,6 +218,11 @@ module.exports = exports = class RPC {
|
|
|
192
218
|
}
|
|
193
219
|
|
|
194
220
|
_teardown(err) {
|
|
221
|
+
// Mark the channel as closed so that any calls made from here on are
|
|
222
|
+
// rejected or destroyed immediately rather than left hanging.
|
|
223
|
+
this._closed = true
|
|
224
|
+
this._error = err
|
|
225
|
+
|
|
195
226
|
this._ondrain(err)
|
|
196
227
|
|
|
197
228
|
// Reject any request awaiting a plain reply. Requests whose response is
|
package/lib/outgoing-request.js
CHANGED
|
@@ -46,6 +46,12 @@ module.exports = class RPCOutgoingRequest {
|
|
|
46
46
|
|
|
47
47
|
this.received = true
|
|
48
48
|
|
|
49
|
+
// If the channel was torn down before a response arrived there is nothing
|
|
50
|
+
// left to await, so reject with the teardown error rather than hang. This
|
|
51
|
+
// covers both requests sent after teardown and requests still awaiting a
|
|
52
|
+
// reply when teardown happens.
|
|
53
|
+
if (this.rpc._closed && !this._responded) this._reject(this.rpc._error)
|
|
54
|
+
|
|
49
55
|
return encoding ? this._promise.then((data) => c.decode(encoding, data)) : this._promise
|
|
50
56
|
}
|
|
51
57
|
|