在 Odoo15 上继承 class 工人

Inherit class Worker on Odoo15

在我的 Odoo 安装之一中,我需要直接从 Python 代码设置 WorkerHTTP class 的 socket_timeout 变量,绕过环境变量 ODOO_HTTP_SOCKET_TIMEOUT 的使用。

如果您从未读过它,可以在此处查看更多信息:https://github.com/odoo/odoo/commit/49e3fd102f11408df00f2c3f6360f52143911d74#diff-b4207a4658979fdb11f2f2fa0277f483b4e81ba59ed67a5e84ee260d5837ef6d

在我使用的 Odoo15 中,Worker classes 位于 odoo/service/server.py

我的想法是继承 Worker class 的构造函数并简单地设置 self.sock_timeout = 10 或其他值,但我无法使其与继承一起工作。

编辑:我几乎成功了,但静态方法有问题。

第 1 步:

继承WorkerHTTP构造函数并添加self.socket_timeout = 10

然后,我还必须继承 PreforkServer 并覆盖 process_spawn() 方法,这样我就可以传递 WorkerHttpExtend 而不是 WorkerHTTP,作为 worker_spawn() 方法的参数。

class WorkerHttpExtend(WorkerHTTP):
    """ Setup sock_timeout class variable when WorkerHTTP object gets initialized"""
    def __init__(self, multi):
        super(WorkerHttpExtend, self).__init__(multi)
        self.sock_timeout = 10
        logging.info(f'SOCKET TIMEOUT: {self.sock_timeout}')


class PreforkServerExtend(PreforkServer):
    """ I have to inherit PreforkServer and override process_spawn() 
    method so I can pass WorkerHttpExtend
    instead of WorkerHTTP, as argument for worker_spawn() method.
    """

    def process_spawn(self):
        if config['http_enable']:
            while len(self.workers_http) < self.population:
                self.worker_spawn(WorkerHttpExtend, self.workers_http)
            if not self.long_polling_pid:
                self.long_polling_spawn()
        while len(self.workers_cron) < config['max_cron_threads']:
            self.worker_spawn(WorkerCron, self.workers_cron)

第 2 步:

静态方法 start() 应该使用 PreforkServerExtend 初始化 PreforkServer,而不是使用 PreforkServer(下面代码的最后一行)。这是我开始遇到问题的地方。

def start(preload=None, stop=False):
   """Start the odoo http server and cron processor."""

  global server
    load_server_wide_modules()
    if odoo.evented:
        server = GeventServer(odoo.service.wsgi_server.application)
    elif config['workers']:
        if config['test_enable'] or config['test_file']:
            _logger.warning("Unit testing in workers mode could fail; use --workers 0.")
        server = PreforkServer(odoo.service.wsgi_server.application)

第 3 步: 在这一点上,如果我想更进一步(我做了),我应该复制整个 start() 方法并导入我需要的所有包以使其工作

import odoo
from odoo.service.server import WorkerHTTP, WorkerCron, PreforkServer, load_server_wide_modules, \
    GeventServer, _logger, ThreadedServer, inotify, FSWatcherInotify, watchdog, FSWatcherWatchdog, _reexec
from odoo.tools import config

我做到了,然后在我的自定义 start() 方法中我写了行

server = PreforkServerExtend(odoo.service.wsgi_server.application)

但即便如此,我如何指示执行我的 start() 方法,而不是原来的方法?

我确信这最终会起作用(也许不安全,但会起作用)因为在某些时候我不是 100% 确定我在做什么,所以我把我的继承 classes WorkerHttpExtend和 PreforkServerExtend 在原始 odoo/service/server.py 中,并使用 PreforkServerExtend 而不是 PreforkServer.

初始化服务器对象
server = PreforkServer(odoo.service.wsgi_server.application)

然后工作:我在 Odoo 服务启动时获得自定义套接字超时值、打印和日志信息,因为 PreforkServerExtend 将在此时调用级联上的自定义 class,否则我继承的 class 是在那里,但他们永远不会被调用。

所以我想如果我可以告诉系统 运行 我的 start() 方法我会做到的。

第 4 步(尚未达到):

我很确定在 odoo/cli/server.py 中调用了 start() 方法,在 main() 方法中:

rc = odoo.service.server.start(preload=preload, stop=stop)

我可以更深入,但我认为我的努力不值得我需要的东西。 所以从技术上讲,如果我能够告诉系统选择哪种 start() 方法,我就会这样做。仍然不确定它是否安全(实际上可能不多,但此时我只是在试验),但我想知道是否有更简单的方法来设置套接字超时而不使用环境变量 ODOO_HTTP_SOCKET_TIMEOUT.

我很确定有比我现在做的更简单的方法,低级别 python 或者甚至 odoo/service/server 中的 class,但我不能'暂时想不通。如果有人有想法,请告诉我!

工作解决方案:在此 post

中引入 Monkeypatch

通过修补 class WorkerHTTP

的 process_request 属性解决
import errno
import fcntl
import socket
import odoo
import odoo.service.server as srv

class WorkerHttpProcessRequestPatch(srv.WorkerHTTP):

    def process_request(self, client, addr):
        client.setblocking(1)
        # client.settimeout(self.sock_timeout)
        client.settimeout(10) # patching timeout setup to a needed value
        client.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

        flags = fcntl.fcntl(client, fcntl.F_GETFD) | fcntl.FD_CLOEXEC
        fcntl.fcntl(client, fcntl.F_SETFD, flags)
        self.server.socket = client
        try:
            self.server.process_request(client, addr)
        except IOError as e:
            if e.errno != errno.EPIPE:
                raise
        self.request_count += 1

# Switch process_request class attribute - this is what I needed to make it work
odoo.service.server.WorkerHTTP.process_request = WorkerHttpProcessRequestPatch.process_request