odoo17后台启动过程3——三种server

文件位置:odoo\service\server.py

1、三种server:

在这里插入图片描述

1.1、Threaded

这是Odoo默认的选项,线程模式,我们知道python的多线程并不是真正的多线程,所以,这种模式下,并发性能较低,也无法利用多核的优势。 优点是比较安全,兼容型号,如果对并发要求不高,这种模式是没有问题的。这也是odoo默认的模式。

1.2、Gevented

利用了python协程,需要预先安装Gevent库,提高了并发西性能,但是安全性和兼容性可能不太好,需要多做测试。
我尝试在windows下通过下列命令启动odoo,但是老是报错, 暂时不去管它了

python odoo-bin gevent -c odoo.conf

1.3、Prefork

可以充分利用多核处理器,它其实是一种多进程模式,由多个进程来处理web请求。

这三种网关有一个共同的父类CommonServer


class CommonServer(object):
    _on_stop_funcs = []

    def __init__(self, app):
        self.app = app
        # config
        self.interface = config['http_interface'] or '0.0.0.0'
        self.port = config['http_port']
        # runtime
        self.pid = os.getpid()

    def close_socket(self, sock):
        """ Closes a socket instance cleanly
        :param sock: the network socket to close
        :type sock: socket.socket
        """
        try:
            sock.shutdown(socket.SHUT_RDWR)
        except socket.error as e:
            if e.errno == errno.EBADF:
                # Werkzeug > 0.9.6 closes the socket itself (see commit
                # https://github.com/mitsuhiko/werkzeug/commit/4d8ca089)
                return
            # On OSX, socket shutdowns both sides if any side closes it
            # causing an error 57 'Socket is not connected' on shutdown
            # of the other side (or something), see
            # http://bugs.python.org/issue4397
            # note: stdlib fixed test, not behavior
            if e.errno != errno.ENOTCONN or platform.system() not in ['Darwin', 'Windows']:
                raise
        sock.close()

    @classmethod
    def on_stop(cls, func):
        """ Register a cleanup function to be executed when the server stops """
        cls._on_stop_funcs.append(func)

    def stop(self):
        for func in type(self)._on_stop_funcs:
            try:
                _logger.debug("on_close call %s", func)
                func()
            except Exception:
                _logger.warning("Exception in %s", func.__name__, exc_info=True)

1、构造函数需要传入一个app
2、提供了几个关闭服务的方法

2、start函数

这是一个入口函数,cli.server 就是通过调用这个函数来启动服务

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

看看它的代码


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.http.root)
    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.http.root)

        # Workaround for Python issue24291, fixed in 3.6 (see Python issue26721)
        if sys.version_info[:2] == (3,5):
            # turn on buffering also for wfile, to avoid partial writes (Default buffer = 8k)
            werkzeug.serving.WSGIRequestHandler.wbufsize = -1
    else:
        if platform.system() == "Linux" and sys.maxsize > 2**32 and "MALLOC_ARENA_MAX" not in os.environ:
            # glibc's malloc() uses arenas [1] in order to efficiently handle memory allocation of multi-threaded
            # applications. This allows better memory allocation handling in case of multiple threads that
            # would be using malloc() concurrently [2].
            # Due to the python's GIL, this optimization have no effect on multithreaded python programs.
            # Unfortunately, a downside of creating one arena per cpu core is the increase of virtual memory
            # which Odoo is based upon in order to limit the memory usage for threaded workers.
            # On 32bit systems the default size of an arena is 512K while on 64bit systems it's 64M [3],
            # hence a threaded worker will quickly reach it's default memory soft limit upon concurrent requests.
            # We therefore set the maximum arenas allowed to 2 unless the MALLOC_ARENA_MAX env variable is set.
            # Note: Setting MALLOC_ARENA_MAX=0 allow to explicitly set the default glibs's malloc() behaviour.
            #
            # [1] https://sourceware.org/glibc/wiki/MallocInternals#Arenas_and_Heaps
            # [2] https://www.gnu.org/software/libc/manual/html_node/The-GNU-Allocator.html
            # [3] https://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=00ce48c;hb=0a8262a#l862
            try:
                import ctypes
                libc = ctypes.CDLL("libc.so.6")
                M_ARENA_MAX = -8
                assert libc.mallopt(ctypes.c_int(M_ARENA_MAX), ctypes.c_int(2))
            except Exception:
                _logger.warning("Could not set ARENA_MAX through mallopt()")
        server = ThreadedServer(odoo.http.root)

    watcher = None
    if 'reload' in config['dev_mode'] and not odoo.evented:
        if inotify:
            watcher = FSWatcherInotify()
            watcher.start()
        elif watchdog:
            watcher = FSWatcherWatchdog()
            watcher.start()
        else:
            if os.name == 'posix' and platform.system() != 'Darwin':
                module = 'inotify'
            else:
                module = 'watchdog'
            _logger.warning("'%s' module not installed. Code autoreload feature is disabled", module)

    rc = server.run(preload, stop)

    if watcher:
        watcher.stop()
    # like the legend of the phoenix, all ends with beginnings
    if getattr(odoo, 'phoenix', False):
        _reexec()

    return rc if rc else 0

1、调用了load_server_wide_modules函数,实际上就是加载base和web两个模块。
2、根据配置和命令行参数来决定启动哪一种服务,并通过odoo.http.rootd对象来初始化server,三种网关都是用这个对象来初始化化

server = ThreadedServer(odoo.http.root)

3、调用server的run方法启动服务

rc = server.run(preload, stop)

3、class ThreadedServer(CommonServer)

先看看run这个入口方法:

    def run(self, preload=None, stop=False):
        """ Start the http server and the cron thread then wait for a signal.

        The first SIGINT or SIGTERM signal will initiate a graceful shutdown while
        a second one if any will force an immediate exit.
        """
        self.start(stop=stop)

从注释中可以看出,该函数启动http server 和cron线程,然后就等待信号。

3.1 启动httpserver

在run方法中调用了 self.start(stop=stop) 来启动http服务。
在start方法中首先绑定了信号处理函数,然后调用了http_spawn 方法。

    def start(self, stop=False):
        _logger.debug("Setting signal handlers")
        set_limit_memory_hard()
        if os.name == 'posix':
            signal.signal(signal.SIGINT, self.signal_handler)
            signal.signal(signal.SIGTERM, self.signal_handler)
            signal.signal(signal.SIGCHLD, self.signal_handler)
            signal.signal(signal.SIGHUP, self.signal_handler)
            signal.signal(signal.SIGXCPU, self.signal_handler)
            signal.signal(signal.SIGQUIT, dumpstacks)
            signal.signal(signal.SIGUSR1, log_ormcache_stats)
        elif os.name == 'nt':
            import win32api
            win32api.SetConsoleCtrlHandler(lambda sig: self.signal_handler(sig, None), 1)

        test_mode = config['test_enable'] or config['test_file']
        if test_mode or (config['http_enable'] and not stop):
            # some tests need the http daemon to be available...
            self.http_spawn()

http_spawn启动了一个后台线程,线程的执行函数是http_thread,线程名称叫odoo.service.httpd

        t = threading.Thread(target=self.http_thread, name="odoo.service.httpd")
        t.daemon = True
        t.start()

而http_thread 启动了一个ThreadedWSGIServerReloadable服务,并且调用了它的serve_forever方法,这估计是一个死循环,一直等待web请求。

    def http_thread(self):
        self.httpd = ThreadedWSGIServerReloadable(self.interface, self.port, self.app)
        self.httpd.serve_forever()

到这里http服务线程就启动好了.

3.2 启动cron线程

server的run方法中还需要启动后台服务线程,一般是2个

        self.cron_spawn()

这个代码比较简单,根据max_cron_threads 参数来启动后台任务线程。

    def cron_spawn(self):
        """ Start the above runner function in a daemon thread.

        The thread is a typical daemon thread: it will never quit and must be
        terminated when the main process exits - with no consequence (the processing
        threads it spawns are not marked daemon).

        """
        # Force call to strptime just before starting the cron thread
        # to prevent time.strptime AttributeError within the thread.
        # See: http://bugs.python.org/issue7980
        datetime.datetime.strptime('2012-01-01', '%Y-%m-%d')
        for i in range(odoo.tools.config['max_cron_threads']):
            def target():
                self.cron_thread(i)
            t = threading.Thread(target=target, name="odoo.service.cron.cron%d" % i)
            t.daemon = True
            t.type = 'cron'
            t.start()
            _logger.debug("cron%d started!" % i)

到这里,一个主线程,一个http服务线程和两个cron线程就启动好了
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/286201.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用拉普拉斯算子的图像锐化的python代码实现——数字图像处理

原理 拉普拉斯算子是一个二阶导数算子,用于图像处理中的边缘检测。它通过计算图像亮度的二阶空间导数来工作,能够突出显示图像中的快速变化区域,如边缘。 图像锐化的原理: 图像锐化是指增强图像中的边缘和细节,使图像…

Python基础知识:整理1 使用函数实现银行ATM操作

定义一个全局变量: money, 用来记录银行卡余额(默认为5000000) 定义一个全局变量: name, 用来记录客户姓名(启动程序时输入) 定义如下函数: 查询余额的函数; 存款函数; 取…

blender mix节点和它的混合模式

Mix 节点是一种用于混合两个颜色或者两个图像的节点,它有以下几个输入和输出: Color1:用于接收第一个颜色或者图像,也就是基色。Color2:用于接收第二个颜色或者图像,也就是混合色。Fac:用于控制…

第六节、项目支付功能实战-保证金支付、支付回调

摘要 上一节中,我们申请了商户的证书、APIv3密钥,以及编写了微信平台证书的下载的相关代码,并以微信平台证书下载和微信下单接口为例分析了sdkapi的使用、sdk是如何封装加签和验签的流程的。这一节我们将结合实际保证金支付业务来实现整个支付的功能。 功能实现 1、实现小…

RDS快速入门

目录 实例创建 设置白名单 RDS(Relational Database Service)是一种托管式的关系型数据库服务,它为用户提供了一种简单、可靠、安全的方式来部署、操作和扩展数据库。具有安全可靠、解决运维烦恼、有效降低成本和自研增加等四大特性&#x…

chromium通信系统-ipcz系统(九)-ipcz系统代码实现-跨Node通信-代理和代理消除

chromium通信系统-ipcz系统(六)-ipcz系统代码实现-跨Node通信-基础通信 一文我们分析了跨Node的基础通信过程。 a进程和b进程通信的过程。 但在程序中a进程将自己打开的一对portal中的一个portal传递给了b进程。由于篇幅问题这个过程我们并没有分析,这篇文章我们就来…

学习MySQL(5.7)第二战:四大引擎、账号管理以及建库(干货满满)

目录 前言: 一.数据库存储引擎 1.存储引擎简介 存储引擎查看 support字段说明 2.四大引擎详细介绍 InnoDB MylSAM MEMORY Archive 二.数据库管理 1.元数据库简介 2.元数据库分类 infomation_schema mysql performance_schema ​编辑3.数据库…

协议基础笔记

Android串口使用方法_android-serialport的使用-CSDN博客 安卓与串口通信-基础篇_安卓串口通信-CSDN博客 串口简介 串口通信是Android智能硬件开发所必须具备的能力,市面上类型众多的外设基本都是通过串口进行数据传输的,所以说不会串口通信根本就做不…

亚马逊鲲鹏系统给我带来的真实体验感

我想分享一下我对亚马逊鲲鹏系统的使用体验。我一直在寻找一个方便且高效的方法来批量注册亚马逊买家账号,而亚马逊鲲鹏系统给了我一个理想的解决方案。 使用亚马逊鲲鹏系统进行批量注册是非常简便的。系统内置了全自动化的操作功能,只要提前准备好所需的…

华为交换机入门(六):VLAN的配置

VLAN(Virtual Local Area Network)即虚拟局域网,是将一个物理的LAN在逻辑上划分成多个广播域的通信技术。VLAN内的主机间可以直接通信,而VLAN间不能直接互通,从而将广播报文限制在一个VLAN内。 VLAN 主要用来解决如何…

Java-执行系统命令进程-实践篇

1 需求 2 接口 3 示例 import java.io.IOException;/*** 现象:1输出后马上输出2* 原因:子进程如果没有调用waitFor(),不会阻塞主进程*/ public class Test {public static void main(String[] args) {System.out.println(1);try {Runtime.ge…

全局异常和自定义异常处理

全局异常GlobalException.java,basePackages:controller层所在的包全路径 import com.guet.score_management_system.common.domian.AjaxResult; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bi…

CMake是什么?为什么学习CMake

文章目录 1.CMake简介2.为什么要学习CMake3.什么样的项目需要用CMake3.1大型或复杂项目3.2跨平台项目3.3需要高度定制化构建的项目3.4 研究和开源项目3.5小型或简单项目 4.CMake的作用5.支持的编译器5.1Windows平台5.2Unix/Linux平台5.3macOS平台5.4其他编译器5.5支持的平台 CM…

“AI+低代码”推动高等教育变革:腾讯云携手同济大学共探数智化

引言 近年来,数字化转型已成为各行各业提高运营效率和生产力的重要手段。而对于高校来说,转型已成为建设高质量教育体系的重要策略。但相较于迈出较早一步的企业群体,本身缺乏技术基因和运营成本的学校在数字化的转型上还较为滞后。 如何改变…

图神经网络——图学习

图学习 0. 前言1. 图2. 图学习3. 图神经网络小结 0. 前言 近年来,从社交网络到分子生物学等各个领域,数据的图表示越来越普遍。图神经网络 (Graph Neural Network, GNN) 是专为处理图结构数据而设计的,要充分挖掘图表示的潜力,深…

软件测试/测试开发丨接口测试学习笔记分享

一、Mock 测试 1、Mock 测试的场景 前后端数据交互第三方系统数据交互硬件设备解耦 2、Mock 测试的价值与意义 不依赖第三方数据节省工作量节省联调 3、Mock 核心要素 匹配规则:mock的接口,改哪些接口,接口哪里的数据模拟响应 4、mock实…

DevC++ easyx实现视口编辑--像素绘图板与贴图系统

到了最终成果阶段了,虽然中间有一些代码讲起来没有意思,纯靠debug,1-1解决贴图网格不重合问题,这次是一个分支结束。 想着就是把瓦片贴进大地图里。 延续这几篇帖子,开发时间也从2023年的4月16到了6月2号,80小时基本…

【Linux】进程控制深度了解

> 作者简介:დ旧言~,目前大二,现在学习Java,c,c,Python等 > 座右铭:松树千年终是朽,槿花一日自为荣。 > 目标:熟练掌握Linux下的进程控制 > 毒鸡汤&#xff…

Spring Boot快速搭建一个简易商城项目【四,优化购物车篇】

在之前的基础上继续将购物车进行完善:全选,删除,加减购物车数量 效果: 全选: 计算价格: //计算总价function jisuan(){let total 0;$(".th").each((i,el)>{//each遍历 i下标 el指的是当前的…

Goole上架年度总结(2023年)

今天来总结一下2023年关于谷歌商店上架的相关政策改动和对应的拒审解决方法。 目录 政策更新与改动2023 年 2 月 22 日2023 年 4 月5 日2023 年 7 月 12 日2023 年 10 月 25 日 开发者计划政策拒审邮件内容和解决办法 政策更新与改动 2023 年 2 月 22 日 生效日期&#xff1…