diag: trigger on this branch, since workflow_dispatch needs the defau… #1
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Diag pipe holder | |
| # THROWAWAY. This exists to answer one question and then be deleted: when the | |
| # conformance run finishes but its output pipe does not close, WHICH process is | |
| # holding the write end? | |
| # | |
| # It runs only on its own throwaway branch. A workflow_dispatch alone is not | |
| # dispatchable until the file exists on the default branch, which is exactly | |
| # what this must not do. | |
| on: | |
| push: | |
| branches: [diag/pipe-holder] | |
| workflow_dispatch: | |
| jobs: | |
| diag: | |
| runs-on: ubuntu-latest | |
| # The work finishes in under three minutes. Anything past that is the hang, | |
| # and there is no reason to buy 45 minutes of it again. | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: DeterminateSystems/determinate-nix-action@v3 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| - name: Build the Node pty at the pinned commit | |
| run: | | |
| ref=$(cat crates/pty-conformance/node-ref) | |
| git clone --filter=blob:none https://github.com/compoundingtech/pty /tmp/node-pty | |
| git -C /tmp/node-pty checkout --detach "$ref" | |
| (cd /tmp/node-pty && npm ci --silent && npm run build --silent) | |
| - name: Build | |
| run: nix develop --command cargo build --workspace --release | |
| - name: Catch the pipe holder | |
| env: | |
| PTY_NODE_CHECKOUT: /tmp/node-pty | |
| run: | | |
| set -u | |
| mkdir -p target/diag | |
| DIAG=target/diag/holders.txt | |
| PIPE=/tmp/diagpipe | |
| # Every finding is appended to a FILE, as it happens. | |
| # | |
| # Last night's instrumentation lost its evidence twice: `tail` | |
| # buffers until a command ends and a killed command never ends, and | |
| # `tee` could not open its output file. A diagnostic whose whole | |
| # subject is "something is holding a pipe open" must not itself | |
| # depend on a pipe closing, or on surviving to the end. | |
| say() { echo "$(date -u +%H:%M:%S) $*" | tee -a "$DIAG"; } | |
| # A NAMED pipe, so a holder is identifiable by the symlink target of | |
| # its file descriptor rather than by matching inodes. | |
| rm -f "$PIPE"; mkfifo "$PIPE" | |
| cat "$PIPE" > /dev/null & | |
| reader=$! | |
| say "reader pid $reader on $PIPE" | |
| files=$(ls crates/pty-conformance/tests/*.rs \ | |
| | xargs -n1 basename | sed 's/\.rs$//' \ | |
| | awk 'NR % 4 == 2' | tr '\n' ' ') | |
| say "files: $files" | |
| nix develop --command ./scripts/conformance-both.sh \ | |
| --node /tmp/node-pty/bin/pty \ | |
| --rust "$PWD/target/release/pty" \ | |
| --out "$PWD/target/conformance" $files > "$PIPE" 2>&1 & | |
| script=$! | |
| say "script pid $script" | |
| wait "$script" || say "script exited non-zero ($?)" | |
| say "SCRIPT HAS EXITED. The question is whether the pipe closes now." | |
| # Give it five minutes, looking every fifteen seconds. If the reader | |
| # is still alive the write end is still held, and the holders are | |
| # named right here. | |
| for i in $(seq 1 20); do | |
| if ! kill -0 "$reader" 2>/dev/null; then | |
| say "reader exited after ${i} checks — pipe closed, NOT reproduced" | |
| exit 0 | |
| fi | |
| say "--- check $i: reader still alive, scanning for holders ---" | |
| for fd in /proc/[0-9]*/fd/*; do | |
| tgt=$(readlink "$fd" 2>/dev/null) || continue | |
| case "$tgt" in | |
| "$PIPE") | |
| pid=$(echo "$fd" | cut -d/ -f3) | |
| [ "$pid" = "$reader" ] && continue | |
| exe=$(readlink "/proc/$pid/exe" 2>/dev/null || echo '?') | |
| cl=$(tr '\0' ' ' < "/proc/$pid/cmdline" 2>/dev/null | cut -c1-140) | |
| st=$(awk '/^PPid:|^State:/{printf "%s ", $2}' "/proc/$pid/status" 2>/dev/null) | |
| say " HOLDER pid=$pid fd=${fd##*/} state/ppid=$st exe=$exe" | |
| say " cmdline=$cl" | |
| ;; | |
| esac | |
| done | |
| sleep 15 | |
| done | |
| say "REPRODUCED: pipe still open after 5 minutes. Holders are listed above." | |
| kill "$reader" 2>/dev/null || true | |
| exit 1 | |
| - name: Keep the findings | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: pipe-holders | |
| path: target/diag/ | |
| if-no-files-found: error |