Skip to content

Commit 68d363b

Browse files
authored
docs: update parallel-workloads-node-js.md for deadlock information (#7140)
* docs: update parallel-workloads-node-js.md for deadlock information * docs: update parallel-workloads-node-js.md
1 parent 50eaa12 commit 68d363b

File tree

1 file changed

+65
-1
lines changed

1 file changed

+65
-1
lines changed

supplemental-docs/performance/parallel-workloads-node-js.md

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,71 @@ and usage scenario.
130130
operating system. This can manifest as `Error: EMFILE, too many open files`
131131
in Node.js.
132132

133-
## Example Scenario
133+
## Avoiding Streaming Deadlock
134+
135+
Because streaming responses stay open until you completely read or abandon the open stream connection,
136+
the socket limit which you configure and how you handle streams can lead to a deadlock scenario.
137+
138+
#### Example deadlock
139+
140+
In this example, the max socket count is 1. When the Promise concurrency tries to `await`
141+
two simultaneous `getObject` requests, it fails because the streaming response of the first request
142+
is **not** read to completion, while the second `getObject` request is blocked indefinitely.
143+
144+
This can cause your application to time out or the Node.js process to exit with code 13.
145+
146+
```ts
147+
// example: response stream deadlock
148+
const s3 = new S3({
149+
requestHandler: {
150+
httpsAgent: {
151+
maxSockets: 1,
152+
},
153+
},
154+
});
155+
156+
// opens connection in parallel,
157+
// but this await is dangerously placed.
158+
const responses = await Promise.all([
159+
s3.getObject({ Bucket, Key: "1" }),
160+
s3.getObject({ Bucket, Key: "2" }),
161+
]);
162+
163+
// reads streaming body in parallel
164+
await responses.map(get => get.Body.transformToByteArray());
165+
```
166+
167+
#### Recommendation
168+
169+
This doesn't necessarily mean you need to de-parallelize your program.
170+
You can continue to use a socket count lower than your maxmimum parallel load, as long
171+
as the requests do not block each other.
172+
173+
In this example, reading of the body streams is done in a non-blocking way.
174+
175+
```ts
176+
// example: parallel streaming without deadlock
177+
const s3 = new S3({
178+
requestHandler: {
179+
httpsAgent: {
180+
maxSockets: 1,
181+
},
182+
},
183+
});
184+
185+
const responses = ([
186+
s3.getObject({ Bucket, Key: "1" }),
187+
s3.getObject({ Bucket, Key: "2" }),
188+
]);
189+
const objects = responses.map(get => get.Body.transformToByteArray());
190+
191+
// `await` is placed after the stream-handling pipeline has been established.
192+
// because of the socket limit of 1, the two streams will be handled
193+
// sequentially via queueing.
194+
await Promise.all(objects);
195+
```
196+
197+
## Batch Workload Example Scenario
134198

135199
You have 10,000 files to upload to S3.
136200

0 commit comments

Comments
 (0)