使用python-rq在远程服务器上执行长任务

0 投票
3 回答
3279 浏览
提问于 2025-04-18 05:21

我写了一段代码,执行起来非常耗时(需要2到3天),我想把它放到服务器上去执行。这个代码里有很多类和函数相互作用,但最后所有的执行都是通过一个叫做test2的函数来完成的。我发现对我来说,使用任务队列可能是个解决方案,而且我并不需要同时执行多个任务,所以我觉得RQ可能适合我。

#action_test.py

import action2

def test1():
    fl = action2.FollowersList()
    mech = action2.Mechanics()
    manager = action2.Manager()
    manager.launch(mech,fl)
    for i in range(0,10):
        manager.iterate(mech,fl)

def test2():
    messageList = []
    fl = action2.FollowersList()
    mech = action2.Mechanics()
    manager = action2.Manager()
    manager.launch(mech,fl)
    for i in range(0,2000):
        message = manager.iterate(mech,fl)
        messageList.append(message)
    return messageList

我在远程服务器上设置了Redis,并以守护进程模式运行。然后我写了一个简单的模块,主要是把我的test2函数放进队列里。

#app.py

from rq import Connection, Queue
from redis import Redis
from action_test import test2

def main():
    # Tell RQ what Redis connection to use
    redis_conn = Redis()
    q = Queue(connection=redis_conn)  # no args implies the default queue

    # Delay calculation of the multiplication
    job = q.enqueue(test2, timeout = 259200)
    print job.result   # => None

if __name__ == '__main__':
    main()

接着我遇到了一个问题:在python-rq的文档网页上(http://python-rq.org/docs/workers/),说启动一个工作者的方法是从命令行执行

$ rqworker

但是这个工作者并不是以守护进程的方式启动的,因此当我通过ssh连接到这个远程服务器时,如果我的ssh连接断开了,工作者也会停止,这样的情况我并不想要。要在我的代码执行的2到3天里保持ssh连接是很不方便的,这样就违背了我使用python-rq的初衷。有没有什么办法可以解决这个问题?也许python-rq的工作者应该不是从命令行启动,而是以守护进程的方式启动?

3 个回答

0

你可以使用supervisord这个工具。它可以帮助你设置一个后台进程,用来运行任务。而且它的配置也非常简单。

1

根据我的理解,你根本不需要用到 python-rq。消息队列通常是用来在分布式系统中进行通信的,这对那些只想在远程服务器上运行长时间脚本的人来说,实在是太复杂了。你可以直接运行你的脚本,而不需要 rqworker。只需在你的 action_test.py 脚本中添加 if __name__=='__main__': test2(),然后就可以从命令行运行这个脚本了:

python test_action.py

正如你所提到的,当你关闭 SSH 会话时,你的脚本也会被终止。这是因为 Unix/Linux 有一种叫做“信号”的机制:系统会向你的任务发送一个“挂起”信号,也就是 SIGHUP。马丁提到过 nohup,这也是一个可行的解决方案(比如 nohup python test_action.py),但对于一个只想运行长脚本的初学者来说,这有点复杂。

对你来说,更简单的解决办法是使用 screen。Screen 可以创建一个虚拟终端,让你可以从一个 shell 中断开连接,然后再重新连接。如果你已经安装了 screen,只需运行 screen,它就会为你创建一个新的虚拟终端。接下来,像往常一样运行你的程序: python test_action.py。一旦程序启动,按 Ctrl+A 然后按 D 来断开连接。现在你可以断开 SSH 会话,但这个任务会在虚拟终端中继续运行,就好像什么都没发生一样。稍后你可以重新 SSH 到服务器,然后输入 screen -r 来恢复使用那个终端。

更多信息请查看这里: https://unix.stackexchange.com/questions/24658/nohup-vs-screen

1

你可以把这个工作放在后台运行(用&),并把输出结果保存到一个文本文件里(用nohup):

nohup rqworker &

默认情况下,这个输出会写入一个叫nohup.out的文件,放在当前目录下(如果不允许的话,就会放在$HOME/nohup.out)。这样你就可以关闭ssh连接了。

在默认设置下,rq会往这个文件里写很多内容,不过用--quiet这个选项可以减少输出:

nohup rqworker --quiet &

你可以查看man nohup如何在后台启动任务

撰写回答