如何在生产中更新Python应用程序

如何在生产中更新Python应用程序,python,continuous-integration,Python,Continuous Integration,我编写了一个Python应用程序,作为守护进程在Linux服务器上运行。它所做的是收听Rabbitmq主题。无论何时出现新消息,应用程序都会按照以下5个步骤处理消息 查询数据库并获取字符串格式的音频数据 将音频数据转换为WAV 调用深度学习模型对音频进行预测 将WAV上传到S3存储桶 将结果发送回web API 主程序使用多线程运行: for i in range(2): t = threading.Thread(target=process_msg, name='worker-%s'

我编写了一个Python应用程序,作为守护进程在Linux服务器上运行。它所做的是收听Rabbitmq主题。无论何时出现新消息,应用程序都会按照以下5个步骤处理消息

  • 查询数据库并获取字符串格式的音频数据
  • 将音频数据转换为WAV
  • 调用深度学习模型对音频进行预测
  • 将WAV上传到S3存储桶
  • 将结果发送回web API
  • 主程序使用多线程运行:

    for i in range(2):
        t = threading.Thread(target=process_msg, name='worker-%s' % i)
        t.setDaemon(True)
        t.start()
    while True:
        time.sleep(5)
    
    回调函数
    process\u msg
    是执行5个步骤的方法

    目前,我就是这样将更改部署到dev服务器的

  • 杀死应用程序的活动进程
  • 执行
    git pull
    以获取更新
  • 再次启动应用程序

  • 这个手动过程对于开发人员来说是可以的,但是对于生产来说是不好的。因为如果在处理消息的过程中停止应用程序,它将在不完成作业的情况下退出。在不中断流程的情况下,CICD此应用程序的最佳方法是什么?

    有很多方法可以做到这一点。 这是我能想到的最简单的方法

    CI/CD

  • 不要将git用作代码交付基础设施。 运行私有pip存储库并每次创建版本化的pip包 你想发布新代码-你还需要控制要发布的功能

  • 使用Jenkins使流程自动化

  • 当您需要部署新代码时,只需执行pip安装-U my_app=1.2.3 然后重新启动应用程序

  • 要不中断进程,还需要几个选项

    这里有一个:

    将代码作为服务运行(systemd、systemv、upstart)。
    安装代码(希望使用pip)后,可以使用以下命令
    service my_app restart

    在你的应用程序中添加一些代码来收听SIGTERM 例如:

    每次重新启动应用程序时,此处理程序都将被调用为back,并执行您将写入的逻辑,以便正常关闭

    tldr

    使用Jenkins发布代码的pip包。
    使用Jenkins将pip包部署到目标服务器。
    调整代码以监听系统信号并相应地采取行动

    附言:
    更高级的解决方案可能是(linux唯一的解决方案)将您的代码打包到debian软件包中并发布。

    您可以使用类似的工具来实现这一点

    这很有帮助。两个问题:
    SIGTERM
    是否来自
    service my app stop
    之类的命令?我在主进程中使用多线程来处理rabbitmq消息(添加到main post的代码)。我应该如何确切地等待,直到所有线程在
    hanldler\u stop\u信号中的终止信号发出后完成。是的,默认情况下(使用systemD),发送SIGTERM,然后等待90秒,然后发送SIGKILL。2.hanldler_stop_信号应该在主线程中,它将侦听来自系统的信号。一旦收到信号,将触发该信号。您需要编写逻辑来正确停止任务,您如何等待?这是您需要解决的问题,因为它取决于您的实现。一个想法是:停止从RabByMQ消费,在处理之前使用内部队列存储兔子的任务,然后等到它空了。@ DDD,如果你发现我的答案有用,请考虑接受它。
    
    import signal
    
    def handler_stop_signals(*args, **kwargs):
        """ Handle system signals
        only SIGTERM expected to trigger this"""
    
        logger.info('Shutting down gracefully ')
        # wait for all tasks to finish before exiting 
    
    
    signal.signal(signal.SIGTERM, handler_stop_signals)