Title: Race condition when ending a stream · Issue #40471 · nodejs/node · GitHub
Open Graph Title: Race condition when ending a stream · Issue #40471 · nodejs/node
X Title: Race condition when ending a stream · Issue #40471 · nodejs/node
Description: Version v14.17.5 and v16.11.1 Platform Linux torri 5.13.14 #29 SMP Mon Sep 6 12:28:17 CEST 2021 x86_64 GNU/Linux Subsystem stream What steps will reproduce the bug? Clone https://github.com/julienw/streams-problems Run the script node-st...
Open Graph Description: Version v14.17.5 and v16.11.1 Platform Linux torri 5.13.14 #29 SMP Mon Sep 6 12:28:17 CEST 2021 x86_64 GNU/Linux Subsystem stream What steps will reproduce the bug? Clone https://github.com/julienw...
X Description: Version v14.17.5 and v16.11.1 Platform Linux torri 5.13.14 #29 SMP Mon Sep 6 12:28:17 CEST 2021 x86_64 GNU/Linux Subsystem stream What steps will reproduce the bug? Clone https://github.com/julienw...
Opengraph URL: https://github.com/nodejs/node/issues/40471
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Race condition when ending a stream","articleBody":"### Version\r\n\r\nv14.17.5 and v16.11.1\r\n\r\n### Platform\r\n\r\nLinux torri 5.13.14 #29 SMP Mon Sep 6 12:28:17 CEST 2021 x86_64 GNU/Linux\r\n\r\n### Subsystem\r\n\r\nstream\r\n\r\n### What steps will reproduce the bug?\r\n\r\nClone https://github.com/julienw/streams-problems\r\nRun the script `node-streams.js` with node v14 or node v16.\r\n\r\nHere is the content of this script:\r\n```js\r\nimport Stream, { Writable, PassThrough } from \"stream\";\r\nimport util from \"util\";\r\n\r\nconst pipeline = util.promisify(Stream.pipeline);\r\nconst nextTick = util.promisify(process.nextTick);\r\n\r\n// This Transform cheaply checks that a gzipped stream looks like a json.\r\nclass MyStream extends Writable {\r\n _write(chunk, encoding, callback) {\r\n console.log(\"_write\", chunk);\r\n callback();\r\n // Calling end will also stop any piping gracefully.\r\n // Using nextTick allows some bufferred write to finish.\r\n process.nextTick(() => this.end());\r\n }\r\n\r\n // This is called when all the data has been given to _write and the\r\n // stream is ended.\r\n _final(callback) {\r\n console.log(\"_final()\");\r\n callback();\r\n }\r\n}\r\n\r\nasync function run() {\r\n console.log(\"START TEST\");\r\n const fixture = \"WRITE SOMETHING\";\r\n const checker = new MyStream();\r\n const input = new PassThrough();\r\n const pipelinePromise = pipeline(input, checker);\r\n console.log(\"WRITE 1\");\r\n input.write(fixture.slice(0, 3));\r\n await nextTick();\r\n console.log(\"WRITE 2\");\r\n input.end(fixture.slice(3));\r\n console.log(\"WAIT FOR PIPELINE END\");\r\n await pipelinePromise;\r\n console.log(\"FINISHED\");\r\n}\r\n\r\n// Keeps the node process running\r\nconst intervalId = setInterval(() => {}, 1000);\r\n\r\nconsole.log(\"Starting\");\r\nrun()\r\n .then(() => console.log(\"End!\"))\r\n .catch((e) => console.error(e))\r\n .then(() => clearInterval(intervalId));\r\n```\r\n(This needs to be run with `type:\"module\"` so it's probably easier to clone the repository)\r\n\r\nIn v12, we get this output:\r\n```\r\nStarting\r\nSTART TEST\r\nWRITE 1\r\n_write \u003cBuffer 57 52 49>\r\n_final()\r\nWRITE 2\r\nWAIT FOR PIPELINE END\r\nFINISHED\r\nEnd!\r\n```\r\nBut in v14 and v16 we get this:\r\n```\r\nStarting\r\nSTART TEST\r\nWRITE 1\r\n_write \u003cBuffer 57 52 49>\r\n_final()\r\nWRITE 2\r\nWAIT FOR PIPELINE END\r\n```\r\nAnd this never ends.\r\n\r\nAs you see, we're calling `this.end()` in `_write()` after a nextTick. The original idea was that this stream's purpose was finished (checking something) and calling `end` would unpipe, and we wouldn't get more writes. The goal is to stop doing more work.\r\n\r\n### How often does it reproduce? Is there a required condition?\r\n\r\nAlways\r\n\r\n### What is the expected behavior?\r\n\r\nI think we should get one of these results:\r\n1. like v12, the pipeline is unpiped and therefore it should end because Passthrough will just finish consuming the data. (I think)\r\n2. otherwise, we should get an error because we're trying to write after `end` (`[ERR_STREAM_WRITE_AFTER_END]: write after end`).\r\n\r\n\r\n### What do you see instead?\r\n\r\nHere it looks like that the pipeline isn't unpiped AND we don't get an error. So the written data isn't consumed by the stream that's been ended, and we're waiting forever.\r\n\r\n\r\n### Additional information\r\n\r\nReplacing `process.nextTick(() => this.end());` with something like `await nextTick(); this.end();` gets an error (behavior 2 above), ~~which is different than node v12~~ but at least we're not waiting forever and we get some clue. __Update Oct 18__: we get the same error in v12 and v14, but in v16 we get the behavior of waiting forever.\r\n\r\nAny insight will be very much appreciated. Especially can you point to what changed in v14 in this topic compared to v12 (I do know that a lot of the streams code changed in-between)? Also it seems to be than waiting forever isn't the right behavior.\r\n\r\nThanks!","author":{"url":"https://github.com/julienw","@type":"Person","name":"julienw"},"datePublished":"2021-10-15T18:01:52Z","url":"https://github.com/nodejs/node/issues/40471"}
| react-profiling | 0 |
| react-import-map | react,react-dom,react-dom/client,react-dom/profiling,react-is,react-reconciler,react/compiler-runtime,react/jsx-dev-runtime,react/jsx-runtime,scheduler@d5750093facf |
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:d0f6feea-7b78-497b-6bf2-8868a0be50f0 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | D5B8:35D054:694950:88CAFD:6AED2DE0 |
| html-safe-nonce | d18e7a89d49dc933da9e589cab14902db5ed873c3371d8f075fcf640defa2412 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJENUI4OjM1RDA1NDo2OTQ5NTA6ODhDQUZEOjZBRUQyREUwIiwidmlzaXRvcl9pZCI6IjkwODAzODU3NzQxMzY2Njc2MTYiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | 65bb09b81f8cee38e9fad5f132c2a08c6f75276b7be724fdfef8bce3b42a197f |
| hovercard-subject-tag | issue:1027674079 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/nodejs/node/40471/issue_layout |
| twitter:image | https://opengraph.githubassets.com/1c498e550d2c5883460337665a9e08583773d86ce654cd77ea63f17d8b695eec/nodejs/node/issues/40471 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/1c498e550d2c5883460337665a9e08583773d86ce654cd77ea63f17d8b695eec/nodejs/node/issues/40471 |
| og:image:alt | Version v14.17.5 and v16.11.1 Platform Linux torri 5.13.14 #29 SMP Mon Sep 6 12:28:17 CEST 2021 x86_64 GNU/Linux Subsystem stream What steps will reproduce the bug? Clone https://github.com/julienw... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | julienw |
| hostname | github.com |
| expected-hostname | github.com |
| None | e51d0b7b5ab34b1688c05b54c3ed17b8658b2fa9bca973a9c740683ccb12cf4a |
| turbo-cache-control | no-preview |
| go-import | github.com/nodejs/node git https://github.com/nodejs/node.git |
| octolytics-dimension-user_id | 9950313 |
| octolytics-dimension-user_login | nodejs |
| octolytics-dimension-repository_id | 27193779 |
| octolytics-dimension-repository_nwo | nodejs/node |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 27193779 |
| octolytics-dimension-repository_network_root_nwo | nodejs/node |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 59ebb7b901cc154ecc179a44f266fcf69f343b30 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
| react-app-name | issues |
Links:
Viewport: width=device-width