简体   繁体   English

在 Odoo15 上继承类 Worker

[英]Inherit class Worker on Odoo15

In one of my Odoo installation I need to setup the socket_timeout variable of WorkerHTTP class directly from Python code, bypassing the usage of environment variable ODOO_HTTP_SOCKET_TIMEOUT.在我的 Odoo 安装之一中,我需要直接从 Python 代码设置 WorkerHTTP 类的 socket_timeout 变量,绕过环境变量 ODOO_HTTP_SOCKET_TIMEOUT 的使用。

If you never read about it, you can check here for more info: https://github.com/odoo/odoo/commit/49e3fd102f11408df00f2c3f6360f52143911d74#diff-b4207a4658979fdb11f2f2fa0277f483b4e81ba59ed67a5e84ee260d5837ef6d如果你从未读过它,你可以在这里查看更多信息: https ://github.com/odoo/odoo/commit/49e3fd102f11408df00f2c3f6360f52143911d74#diff-b4207a4658979fdb11f2f2fa0277f483b4e81ba59ed67a5e84ee260dd5837

In Odoo15, which i'm using, Worker classes are located at odoo/service/server.py在我正在使用的 Odoo15 中,Worker 类位于 odoo/service/server.py

My idea was to inherit constructor for Worker class and simply setup self.sock_timeout = 10 or another value, but I can't make it work with inheritance.我的想法是继承 Worker 类的构造函数并简单地设置 self.sock_timeout = 10 或其他值,但我不能让它与继承一起工作。

EDIT: I almost managed it to work, but I have problems with static methods.编辑:我几乎设法让它工作,但我有静态方法的问题。

STEP 1:步骤1:

Inherit WorkerHTTP constructor and add self.socket_timeout = 10继承 WorkerHTTP 构造函数并添加 self.socket_timeout = 10

Then, I also have to inherit PreforkServer and override process_spawn() method so I can pass WorkerHttpExtend instead of WorkerHTTP, as argument for worker_spawn() method.然后,我还必须继承 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)

STEP 2:第2步:

static method start() should initialize PreforkServer with PreforkServerExtend, not with PreforkServer (last line in the code below).静态方法 start() 应该使用 PreforkServerExtend 初始化 PreforkServer,而不是使用 PreforkServer(下面代码中的最后一行)。 This is where I start to have problems.这是我开始遇到问题的地方。

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)

STEP 3: At this point if I wanna go further (which I did) I should copy the whole start() method and import all package I need to make it work第 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

I did it and then in my custom start() method I wrote line我做到了,然后在我的自定义 start() 方法中我写了一行

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

but even then, how do I tell to execute my start() method, instead of the original one??但即便如此,我如何告诉执行我的 start() 方法,而不是原来的?

I'm sure this would eventually work (mabe not safely, but would work) because at some point I wasn't 100% sure what I was doing, so I put my inherit classes WorkerHttpExtend and PreforkServerExtend in the original odoo/service/server.py and initialized server obj with PreforkServerExtend instead of PreforkServer.我确信这最终会起作用(可能不安全,但会起作用),因为在某些时候我不是 100% 确定我在做什么,所以我把我的继承类 WorkerHttpExtend 和 PreforkServerExtend 放在原来的 odoo/service/server .py 并使用 PreforkServerExtend 而不是 PreforkServer 初始化服务器 obj。

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

It works then: I get custom socket timeout value, print and logging info when Odoo service start, because PreforkServerExtend will call custom class on cascade at that point, otherwise my inherited class are there but they will never be called.然后它起作用了:当 Odoo 服务启动时,我得到自定义套接字超时值、打印和日志信息,因为 PreforkServerExtend 将在此时级联调用自定义类,否则我继承的类在那里但它们永远不会被调用。

So I guess if I could tell the system to run my start() method I would have done it.所以我想如果我可以告诉系统运行我的 start() 方法,我会做到的。

STEP 4 (not reached yet):第 4 步(尚未达到):

I'm pretty sure that start() method is called in odoo/cli/server.py, in main() method:我很确定在 odoo/cli/server.py 中调用了 start() 方法,在 main() 方法中:

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

I could go deeper but I don't think the effort is worth for what I need.我可以更深入,但我认为这些努力不值得我需要。 So technically if I would be able to tell the system which start() method to choose, I would have done it.所以从技术上讲,如果我能够告诉系统选择哪个 start() 方法,我会做到的。 Still not sure it is safe procedure (probably not much actually, but at this point I was just experimenting), but I wonder if there is an easier method to set up socket timeout without using environment variable ODOO_HTTP_SOCKET_TIMEOUT.仍然不确定它是否安全(实际上可能并不多,但此时我只是在试验),但我想知道是否有更简单的方法来设置套接字超时而不使用环境变量 ODOO_HTTP_SOCKET_TIMEOUT。

I'm pretty sure there is an easier method than i'm doing, with low level python or maybe even with a class in odoo/service/server, but I can't figure out for now.我很确定有一个比我正在做的更简单的方法,使用低级 python,甚至可能使用 odoo/service/server 中的类,但我现在不知道。 If some one has an idea, let me know!如果有人有想法,请告诉我!

Working solution: Introduced to Monkeypatch in this post工作解决方案:在这篇文章中介绍了 Monkeypatch

Possible for a class to look down at subclass constructor? 一个类可以看不起子类的构造函数吗?

solved by patching process_request attribute of class WorkerHTTP通过修补 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM