vercel / pkg

Package your Node.js project into an executable
https://npmjs.com/pkg
MIT License
24.33k stars 1.01k forks source link

Node Main Thread is Blocked by socket connection #1742

Closed MichaelLeeHobbs closed 2 years ago

MichaelLeeHobbs commented 2 years ago

What version of pkg are you using?

^5.8.0

What version of Node.js are you using?

14.18.0

What operating system are you using?

Windows

What CPU architecture are you using?

x86_64

What Node versions, OSs and CPU architectures are you building for?

node14-win-x64

Describe the Bug

This code when running in pkg window x64 exe blocks the main thread but runs perfectly fine, on windows, linux, wsl, linux container with various version of node12-18. We have basically made a custom ZTNA client that accepts a TCP connection and proxies that over an encrypted tcp connection. What we are seeing is that the application works fine with moving small chunks of data ie a web page proxied over the tls tunnel works. When the application tries to pull a large audio file the proxy app freezes right after these two log messages. To be clear we only see this when we turn the code into an exe.

(server) >>> Sending connection request: ${this.name}
(server) >>> Ready resuming client

The app stays frozen until the client app gives up or is forced closed. During this time the app is completely unresponsive. It has a small express.js component that stops responding which is how we know the main thread is blocked. Once the client is forced closed or gives up then the express component resumes working.

const tls = require("tls")
const logger = require('./logger')()

class ClientSession {
    constructor({client, name, serverPort, serverHost, tlsOptions}) {
        client.pause()

        logger.info(`(server) >>> Opening tls connection to server ${serverHost}:${serverPort}`)
        const server = tls.connect(serverPort, serverHost, tlsOptions, () => {
            // Check if the authorization worked
            if (!server.authorized) {
                const err = "(server) >>> Connection not authorized!!! Error: " + server.authorizationError
                logger.fatal(err)
                throw new Error(err)
            }
        })
        server.on("ready", () => {
            logger.info(`(server) >>> Sending connection request: ${name}`)
            server.write(JSON.stringify({name}))
            logger.debug("(server) >>> Ready resuming client")
            try {
                client.pipe(server)
                server.pipe(client)
                client.resume()

            } catch (e) {
                logger.error('(server) >>> client.resume() error?', e)
                // todo is this needed?
                server.end()
            }
        })
        server.on("error", (err) => {
            logger.error("(server) >>> Caught socket error: ", err)
            // todo is this needed?
            client.end()
        })
        server.on("close", (had_error) => logger.debug(`(server) >>> close, had_error: ${had_error} `))
        // todo is this needed?
        server.on("end", () => client.end())
        // todo is this needed?
        client.on("end", () => server.end())
    }
}

module.exports = ClientSession

Expected Behavior

Not block main thread.

To Reproduce

See bug description.

MichaelLeeHobbs commented 2 years ago

This is a conflict with robot-js. When we built the exe with only the ZTNA code it works as expected.