Skip to content

BUG - Deadlock when using readline or inquirer before spawning a node-pty process #779

@Choppel

Description

@Choppel

Calling readline or inquirer before spawning something via node-pty that expects some input (uses stdin) results in a deadlock.

Test files
package.json

{
  "author": "",
  "dependencies": {
    "@inquirer/prompts": "^7.4.1",
    "@types/node": "^20.17.30",
    "node-pty": "^1.0.0"
  },
  "description": "",
  "keywords": [],
  "license": "ISC",
  "main": "index.js",
  "name": "test",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "type": "module",
  "version": "1.0.0"
}

index.js

import {input} from '@inquirer/prompts';
import {spawn} from 'node-pty';
import process, {stdin, stdout} from 'node:process';
import {createInterface} from 'node:readline/promises';

const callInquirer = async() => {
  await input({
    message: 'Prompt from inquirer'
  });
};

const callReadline = async() => {
  const rl = createInterface({
    input: stdin,
    output: stdout
  });

  await rl.question('Prompt from readline');

  rl.close();
};

const spawnNodePty = () => {
  const ptyProcess = spawn('bash', ['sub.sh'], {});

  process.stdin.on('data', (_data) => ptyProcess.write(_data.toString('utf-8')));

  ptyProcess.onData((_dataFromPty) => process.stdout.write(_dataFromPty));

  ptyProcess.onExit((_result) => {
    process.exit(_result.exitCode);
  });
};

const Test1 = async() => {
  // Read something from stdin via inquirer
  await callInquirer();

  // Spawn the sub.sh file
  spawnNodePty();
};

const Test2 = async() => {
  // Read something from stdin via readline
  await callReadline();

  // Spawn the sub.sh file
  spawnNodePty();
};

const Test3 = async() => {
  // Spawn the sub.sh file
  spawnNodePty();
};

await Test1(); // will deadlock at "Prompt from sub.sh" message
// OR
// await Test2(); // will deadlock at "Prompt from sub.sh" message
// OR
// await Test3(); // will NOT deadlock

sub.sh

#!/bin/bash

read -p "Prompt from sub.sh: " test

Test
The three test cases can be switched by un/-commenting the individual line at the end of index.js.

I suppose the problem has something to do with the reusability of stdin.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions