4

我有一个 python django 应用程序,其中一部分正在解析一个大文件。这需要很长时间,所以我放了一个 fork 来处理处理,让用户继续浏览该站点。在 fork 代码中,有大量对我们托管在亚马逊上的 postgres 数据库的调用。

我收到以下错误:

SSL error: decryption failed or bad record mac

这是代码:

pid = os.fork()
if pid == 0:
    lengthy_code_here(long)
    database_queries(my_database)
    os._exit(0)

我的数据库调用都没有工作,尽管在我插入 fork 之前它们工作得很好。环顾四周后,似乎它可能是一个陈旧的数据库连接,但我不知道如何修复它。有没有人有任何想法?

4

2 回答 2

7

在保持套接字打开(例如数据库连接)的同时进行分叉通常是不安全的,因为两个进程最终会尝试同时使用同一个套接字。

您至少需要在分叉后关闭并重新打开数据库连接。

不过,理想情况下,这可能更适合像Celery这样的任务队列系统。

于 2012-06-13T19:04:15.663 回答
2

生产环境中的 Django 通常有一个进程分派给包含 django/python 的一堆进程。这些过程是长期运行的,即。他们在处理一个请求后不会终止。相反,他们处理一个请求,然后是另一个,然后是另一个,等等。这意味着在服务请求结束时未恢复/清理的更改将影响未来的请求。

当你 fork 一个进程时,子进程会从父进程继承各种东西,包括所有打开的描述符(文件、队列、目录)。即使您对描述符什么都不做,仍然存在问题,因为当一个进程终止时,所有打开的描述符都将被清除。

因此,当您从一个长时间运行的进程中分叉时,您将自己设置为在子进程完成处理后死亡时关闭所有打开的描述符(例如 ssl 连接)。有一些方法可以防止这种情况在分叉中发生,但有时很难做到正确。

更好的设计是不分叉,而是移交给另一个正在运行或以更安全的方式启动的进程。例如:

  • at(1) 可用于将作业排队以供稍后(或立即)执行
  • 消息队列可用于将消息传递给其他守护进程
  • 标准 IPC 结构(例如管道)可用于与其他守护进程通信

更新:

如果要使用 at(1),则必须创建一个独立的脚本。您可以使用序列化程序将数据从 django 传递到脚本。

于 2012-06-13T19:26:22.150 回答