安装psutil模块
进入你想要安装的Python环境,输入如下命令进行模块安装
pip install psutil
如果顺利,那么接下来你就可以使用psutil模块了。
问题review
最近在写一个CI的平台项目,项目的大体要求就是把一些平时需要在终端使用命令行方式的操作,提供一个可视化的web界面,在界面上填写相关信息,点击按钮就可以完成本地命令行的操作。
我采用的策略是通过SSH的方式去连接客户机,然后通过SSH方式去控制客户机的命令行操作。当然其中还涉及到很多技术以及细节,在这里不累述了。
在项目中我使用到了websocket来使客户端与服务端进行长连接,实现服务端主动推送消息到客户端上。当客户端离开当前页面,服务端的socketio就会自动触发disconnect事件,在disconnect事件中我做了如下处理。
存在bug的代码:
@socketio.on('disconnect', namespace='/manager')
def pty_disconnect():
try:
child_process = psutil.Process(session.get(current_user.username).get('child_pid'))
except psutil.NoSuchProcess as err:
disconnect()
session[current_user.username] = {}
return
if child_process.status() in ('running', 'sleeping'):
child_process.terminate()
session[current_user.username] = {}
print('client disconnect, session clear')
socketio.emit('pty-output', {"output": 'Web Socket连接已断开,请刷新页面重新连接!'}, namespace="/manager")
上述代码描述的就是当客户端断开连接之后,服务端会自动销毁该客户端的子进程,并且清楚保存在服务端的session信息。
一开始的时候,代码运作都很正常,当有一次,我点击了进入了这个页面,然后没做任何操作,转到了另外一个页面中去了,然后我的程序自动终止了。
进入该页面时候,客户端就已经连接到了服务端,因此在客户端退出的时候服务端就会自动触发disconnect事件,然后执行上述代码逻辑。我盘查了一下上述代码的逻辑,我我没有发现哪里存在着不妥当的地方。那为什么我进入页面什么都不做,退出页面的时候,我的整个进程就自动被终止了呢??
问题排查
于是乎,我祭出bug排除神器 print()闪亮登场~~~~~ 大家赶紧撒花!!!!
加入了print()后的代码如下
@socketio.on('disconnect', namespace='/manager')
def pty_disconnect():
try:
child_process = psutil.Process(session.get(current_user.username).get('child_pid'))
print('child process is ', child_process)
print('session child process is ', session.get(current_user.username).get('child_pid'))
except psutil.NoSuchProcess as err:
disconnect()
session[current_user.username] = {}
return
if child_process.status() in ('running', 'sleeping'):
child_process.terminate()
session[current_user.username] = {}
print('client disconnect, session clear')
socketio.emit('pty-output', {"output": 'Web Socket连接已断开,请刷新页面重新连接!'}, namespace="/manager")
代码结果输出如下
child process is psutil.Process(pid=15405, name='python', status='running', started='16:08:12')
session child process is None
session存在的为None
,这是正确的,但是通过psutil.Process()
获取到的居然是我当前程序运行的pid,那就知道了为什么当前程序会自动终止了,因为terminate()
函数终止了我们的主进程。
测试
于是乎,我做了如下的测试。
打开一个终端输入如下代码
import psutil
import os
os.getpid()
# 24980
psutil.Process(None)
# psutil.Process(pid=24980, name='python', status='running', started='16:44:47')
发现当我们在Process()
函数中传入None时,就会获取到我们当前主进程的相关信息,这尼玛也太坑了ba~~~ 我不知道这要设计的用意?
然后我们在终端中调用terminate()
方法,结果如下。
我们可以清楚的看到 Process finished with exit code 143.
问题解决
修改了一下代码逻辑,然后这个bug就消失殆尽啦!
@socketio.on('disconnect', namespace='/manager')
def pty_disconnect():
try:
child_id = session.get(current_user.username).get('child_pid')
if child_id is not None:
child_process = psutil.Process(session.get(current_user.username).get('child_pid'))
except psutil.NoSuchProcess as err:
disconnect()
session[current_user.username] = {}
return
if child_process.status() in ('running', 'sleeping'):
child_process.terminate()
session[current_user.username] = {}
print('client disconnect, session clear')
socketio.emit('pty-output', {"output": 'Web Socket连接已断开,请刷新页面重新连接!'}, namespace="/manager")
Note:
我要去看看psutil的文档中有没有说明这个问题,如果没有那么我切不是可以给psutil做个contribution~~~hhhh