Description
Issue observed on two distinct systems:
-
System 1. Linux laptop
- Version: 8.4.0
- Platform: Arch Linux 4.11.9 (x86_64)
-
System 2. Beaglebone Black
- Version: 6.10.3
- Platform: Linux 4.9.41 (armv71)
I'm using fs.ReadStream to continuously read from a character device, e.g. /dev/input/event0
. Receiving events works great, but on attempting to shut down the process does not exit as expected. Googling has turned up similar-sounding issues all the way back to node-0.x, but I have been unable to find a solution.
Code to reproduce (behaves the same on both aforementioned systems):
const fs = require('fs')
const stream = fs.createReadStream('/dev/input/event0')
stream
.on('end', () => { console.log('End') })
.on('open', fd => { console.log(`Opened (fd=${fd})`) })
.on('close', () => { console.log('Closed') })
.on('error', err => { console.log(`Error: ${err}`) })
.on('data', data => { console.log(data) })
setTimeout(() => {
console.log('Attempting to close stream')
stream.on('close', () => {
console.log(`Stream fd is now ${stream.fd}`)
process.exit(0) // Hangs
})
stream.close()
}, 1000)
Output:
Opened (fd=9)
Attempting to close stream
Closed
Stream fd is now null
(Hung here, ^C or kill process to exit)
A few interesting (?) observations:
Explicitly obtaining the file descriptor we get identical results, unless if the .on('data', ...)
listener is not attached, in which case we can exit as expected. Removing the listener in the shutdown process does not work, however, nor do we get this behavior if the fd
is opened by fs.createReadStream
(i.e. simply commenting out the .on('data', ...)
from the first sample. Adjusted sample:
const fs = require('fs')
const fd = fs.openSync('/dev/input/event0', 'r')
const stream = fs.createReadStream('ignored', { fd: fd })
stream
.on('end', () => { console.log('End') })
//.on('open', fd => { console.log(`Opened (fd=${fd})`) }) // No event, as expected
.on('close', () => { console.log('Closed') })
.on('error', err => { console.log(`Error: ${err}`) })
//.on('data', data => { console.log(data) }) // Exit works if commented out
setTimeout(() => {
console.log('Attempting to close stream')
//stream.removeAllListeners('data') // No result
stream.on('close', () => {
console.log(`Stream fd is now ${stream.fd}`)
process.exit(0)
})
stream.close()
//fs.closeSync(fd) // Does not trigger the `close` event
}, 1000)
This is probably not related to the problem, but I get the same result if I "trigger" an end
-event by doing the following in my shutdown routine as such:
// `.push(null)` and `.read(0)` together trigger an `end` event
stream.push(null)
stream.read(0)
Is this a bug, or am I simply missing something? Cheers!