一个进程无法自动退出的问题

让trae给自己写一个hexo-douban的插件,但是发现自己hexo版本有点低,于是按照https://note.weizwz.com/hexo/basic/hexo-update 这里的步骤来进行升级,可升级完成后发现自己就算执行

1
hexo -v

这样的命令都无法自动退出,感觉就是卡死在系统里,按ctrl+c可以自动结束,可这也不是解决方式啊.

那就先看看内存里这个进程到底有什么

1
2
cat /proc/291847/wchan                                                                                                         
do_epoll_wait%

do_epoll_wait 说明进程在事件循环里等 epoll 事件——即有活跃的句柄(socket、定时器、文件监视器)没释放,正常退出的程序最后应该是 exit 而不是停在 epoll。

那就再看看还有哪些文件句柄

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
ls -l /proc/291847/fd                                                                                                         
总计 0
lrwx------ 1 timo timo 64 9月22日 21:35 0 -> /dev/pts/0
lrwx------ 1 timo timo 64 9月22日 21:34 1 -> /dev/pts/0
lr-x------ 1 timo timo 64 9月22日 21:35 10 -> 'pipe:[546415]'
l-wx------ 1 timo timo 64 9月22日 21:35 11 -> 'pipe:[546415]'
lrwx------ 1 timo timo 64 9月22日 21:35 12 -> 'anon_inode:[eventfd]'
lrwx------ 1 timo timo 64 9月22日 21:35 13 -> 'anon_inode:[eventpoll]'
lr-x------ 1 timo timo 64 9月22日 21:35 14 -> 'pipe:[551627]'
l-wx------ 1 timo timo 64 9月22日 21:35 15 -> 'pipe:[551627]'
lrwx------ 1 timo timo 64 9月22日 21:35 16 -> 'anon_inode:[eventfd]'
lrwx------ 1 timo timo 64 9月22日 21:35 17 -> /dev/pts/0
lr-x------ 1 timo timo 64 9月22日 21:35 18 -> /dev/null
lrwx------ 1 timo timo 64 9月22日 21:35 19 -> /dev/pts/0
lrwx------ 1 timo timo 64 9月22日 21:34 2 -> /dev/pts/0
lrwx------ 1 timo timo 64 9月22日 21:35 20 -> 'anon_inode:[eventpoll]'
lr-x------ 1 timo timo 64 9月22日 21:35 21 -> 'pipe:[550467]'
l-wx------ 1 timo timo 64 9月22日 21:35 22 -> 'pipe:[550467]'
lrwx------ 1 timo timo 64 9月22日 21:35 23 -> 'anon_inode:[eventfd]'
lrwx------ 1 timo timo 64 9月22日 21:35 3 -> 'anon_inode:[eventpoll]'
lr-x------ 1 timo timo 64 9月22日 21:35 4 -> 'pipe:[551625]'
l-wx------ 1 timo timo 64 9月22日 21:35 5 -> 'pipe:[551625]'
lr-x------ 1 timo timo 64 9月22日 21:35 6 -> 'pipe:[551626]'
l-wx------ 1 timo timo 64 9月22日 21:35 7 -> 'pipe:[551626]'
lrwx------ 1 timo timo 64 9月22日 21:35 8 -> 'anon_inode:[eventfd]'
lrwx------ 1 timo timo 64 9月22日 21:35 9 -> 'anon_inode:[eventpoll]'

这里发现没有socket,所以就没有网络等待的东西.也没有文件监视,但是有四套”epoll + eventfd + pipe

再看看每个线程的等待执行点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
for t in /proc/291847/task/*; do
echo "$(basename $t) $(cat $t/comm 2>/dev/null) -> $(cat $t/wchan 2>/dev/null)"
done

291847 hexo -> do_epoll_wait
291848 node -> do_epoll_wait
291849 node -> futex_wait_queue
291850 node -> futex_wait_queue
291851 node -> futex_wait_queue
291852 node -> futex_wait_queue
291853 node -> futex_wait_queue
291854 hexo -> futex_wait_queue
291855 hexo -> futex_wait_queue
291856 hexo -> futex_wait_queue
291857 hexo -> futex_wait_queue
291858 hexo -> do_epoll_wait

解读一下

1
2
291847 hexo -> do_epoll_wait    ← 主线程,正常
291848 node -> do_epoll_wait ← 唯一一个多余的、带事件循环的 Worker 线程!

一个在线程名还是node时被创建的 Worker,说明它创建于进程很早期(hexo-cli 改进程名之前),之后它自己的事件循环一直空转,进程自然无法退出。其余线程都是正常的。

那我们就找下node modules里有哪些会用worker线程的.

1
2
3
4
5
6
grep -rl "worker_threads" node_modules --include="*.js"
node_modules/camaro/lean-pool.js
node_modules/camaro/pool-worker.js
node_modules/eslint/lib/eslint/eslint-helpers.js
node_modules/eslint/lib/eslint/eslint.js
node_modules/eslint/lib/eslint/worker.js

这里可以看到都是一个camaro和一个eslint库导致的.而其中eslint是一个使用非常广泛的库,先查camaro这个库

1
npm ls camaro

查了下是hexo-migrator-wordpress是在使用了,这个blog当初是用wordpress的,后来闲性能不行就换成了hexo直接静态页面的.不过模块一直在项目里没有卸载,那这次就卸载了就好了.

1
2
3
4
npm rm hexo-migrator-wordpress

#卸载完再执行一下发现问题解决了
hexo -v

或者用如下方法,这样会产生json文件,可以查下json文件的内容

1
2
3
4
5
# 终端 1
NODE_OPTIONS='--report-on-signal=SIGUSR2' hexo -v

# 终端 2:挂住后
kill -USR2 <新PID>

但是你知道nodejs有这个方法,通用的其实可以这样进行

1
2
ls -l /proc/291848/fd        # 它握着哪些句柄
cat /proc/291848/cmdline

或者直接用strace来看一下到底卡哪里了

1
strace hexo -v