celery 源碼筆記(一)

由于工作需要,開一個celery源碼筆記的坑帚呼。

啟動

從github上下載源碼打開后掏缎,可看到源碼的結構如下:

celery目錄結構

打開setup.py文件,在文件的最后可以看到
1533043004390.png

因此煤杀,可以分析出celery的入口是celery/__main__.py文件的main函數(shù)眷蜈,函數(shù)定義如下

def main():
    """Entrypoint to the ``celery`` umbrella command."""
    if 'multi' not in sys.argv:
        maybe_patch_concurrency()
    from celery.bin.celery import main as _main
    _main()

這里可以看到,main函數(shù)會調(diào)用celery.bin.celery模塊的main()函數(shù)沈自,轉到定義酌儒,在代碼中可以看到這里的主要邏輯為

cmd = CeleryCommand() # 創(chuàng)建CeleryComman對象
cmd.execute_from_commandline(argv) # 從命令行啟動

CeleryCommand對象在celery/bin/celery.py文件,這里可以看到CeleryCommand繼承自Command類(該類的聲明celery/bin/base.py文件酥泛,在很多類都是由該類派生出來今豆,以后會提到)嫌拣,由于CeleryCommand并沒有實現(xiàn)自己的__init__函數(shù)柔袁,因此會調(diào)用Command類的__init__函數(shù)進行初始化

    def __init__(self, app=None, get_app=None, no_color=False,
                 stdout=None, stderr=None, quiet=False, on_error=None,
                 on_usage_error=None):
        self.app = app
        self.get_app = get_app or self._get_default_app
        self.stdout = stdout or sys.stdout
        self.stderr = stderr or sys.stderr
        self._colored = None
        self._no_color = no_color
        self.quiet = quiet
        if not self.description:
            self.description = self._strip_restructeredtext(self.__doc__)
        if on_error:
            self.on_error = on_error
        if on_usage_error:
            self.on_usage_error = on_usage_error

這里我們可以看到__init__執(zhí)行進行了一些簡單的初始化工作。接下來分析execute_from_commandline函數(shù)

    def execute_from_commandline(self, argv=None):
        argv = sys.argv if argv is None else argv
        if 'multi' in argv[1:3]:  # Issue 1008
            self.respects_app_option = False
        try:
            sys.exit(determine_exit_status(
                super(CeleryCommand, self).execute_from_commandline(argv)))
        except KeyboardInterrupt:
            sys.exit(EX_FAILURE)

CeleryCommandexecute_from_commandline函數(shù)中异逐,我們可以看到這里調(diào)用了Command類的execute_from_commandline函數(shù)

    def execute_from_commandline(self, argv=None):
        """Execute application from command-line.

        Arguments:
            argv (List[str]): The list of command-line arguments.
                Defaults to ``sys.argv``.
        """
        if argv is None:
            argv = list(sys.argv)
        # Should we load any special concurrency environment?
        self.maybe_patch_concurrency(argv)
        self.on_concurrency_setup()

        # Dump version and exit if '--version' arg set.
        self.early_version(argv)
        argv = self.setup_app_from_commandline(argv) # 解析命令行參數(shù)并創(chuàng)建Celery實例
        self.prog_name = os.path.basename(argv[0])
        return self.handle_argv(self.prog_name, argv[1:]) # 調(diào)用當前對象的handle_argv函數(shù)

在該函數(shù)中會調(diào)用setup_app_from_commandline解析命令行參數(shù)并創(chuàng)建應用(用戶的app也是在這一步被加載)捶索,之后調(diào)用handle_argv函數(shù)繼續(xù)處理,這里需要注意灰瞻,代碼中調(diào)用的handle_argv函數(shù)是CeleryCommand中定義的腥例,接下來我們分析handle_argv函數(shù)。

    def handle_argv(self, prog_name, argv, **kwargs):
        self.prog_name = self.prepare_prog_name(prog_name)
        argv = self._relocate_args_from_start(argv)
        _, argv = self.prepare_args(None, argv)
        try:
            command = argv[0]
        except IndexError:
            command, argv = 'help', ['help']
        return self.execute(command, argv)

這里可以看到酝润,在解析了參數(shù)之后燎竖,調(diào)用了execute函數(shù),其中第一個參數(shù)為命令行參數(shù)中解析出來的要销,按照官網(wǎng)的示例构回,這里的字符串為"worker",(后面的分析都暫時認為command的值是"worker")疏咐。之后進入到execute函數(shù)中

    def execute(self, command, argv=None):
        try:
            cls = self.commands[command]
        except KeyError:
            cls, argv = self.commands['help'], ['help']
        cls = self.commands.get(command) or self.commands['help'] # 根據(jù)傳入的command字符串獲取對應的類
        try:
            return cls(
                app=self.app, on_error=self.on_error,
                no_color=self.no_color, quiet=self.quiet,
                on_usage_error=partial(self.on_usage_error, command=command),
            ).run_from_argv(self.prog_name, argv[1:], command=argv[0]) # 初始化并啟動實例
        except self.UsageError as exc:
            self.on_usage_error(exc)
            return exc.status
        except self.Error as exc:
            self.on_error(exc)
            return exc.status

這里我們看到execute函數(shù)主要做了兩件事纤掸,一是根據(jù)傳入的command查找類;二是創(chuàng)建上一步的類的實例并啟動浑塞。
轉到worker類的定義借跪,在文件celery/bin/worker.py中,可以看到酌壕,該類也是繼承自Command類掏愁,worker類實例的初始化也是調(diào)用Command類的__init__歇由,初始化完成后會調(diào)用run_from_argv啟動,該函數(shù)只是回調(diào)了一下當前對象的handle_argv函數(shù)果港。由于worker類沒有重寫handle_argv印蓖,因此會調(diào)用Command類中的該函數(shù)。

    def handle_argv(self, prog_name, argv, command=None):
        """Parse arguments from argv and dispatch to :meth:`run`.

        Warning:
            Exits with an error message if :attr:`supports_args` is disabled
            and ``argv`` contains positional arguments.

        Arguments:
            prog_name (str): The program name (``argv[0]``).
            argv (List[str]): Rest of command-line arguments.
        """
        options, args = self.prepare_args(
            *self.parse_options(prog_name, argv, command))
        return self(*args, **options)

在該函數(shù)中京腥,會調(diào)用當前對象的__call__函數(shù)赦肃,同樣地,這里也是調(diào)用Command類中定義的該函數(shù)公浪。該函數(shù)中他宛,會調(diào)用當前對象的run函數(shù),這里調(diào)用的便是worker類中定義的run函數(shù)欠气。在該函數(shù)中厅各,會首先進行一些配置,之后便是創(chuàng)建真正的Worker類的對象之后調(diào)用start函數(shù)啟動预柒。
本階段的調(diào)用時序圖可以整理如下:

啟動時序圖
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末队塘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子宜鸯,更是在濱河造成了極大的恐慌憔古,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件淋袖,死亡現(xiàn)場離奇詭異鸿市,居然都是意外死亡,警方通過查閱死者的電腦和手機即碗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門焰情,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人剥懒,你說我怎么就攤上這事内舟。” “怎么了初橘?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵验游,是天一觀的道長。 經(jīng)常有香客問我壁却,道長批狱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任展东,我火速辦了婚禮赔硫,結果婚禮上,老公的妹妹穿的比我還像新娘盐肃。我一直安慰自己爪膊,他們只是感情好权悟,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著推盛,像睡著了一般峦阁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上耘成,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天榔昔,我揣著相機與錄音,去河邊找鬼瘪菌。 笑死撒会,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的师妙。 我是一名探鬼主播诵肛,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼默穴!你這毒婦竟也來了怔檩?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤蓄诽,失蹤者是張志新(化名)和其女友劉穎薛训,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體若专,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡许蓖,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年蝴猪,在試婚紗的時候發(fā)現(xiàn)自己被綠了调衰。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡自阱,死狀恐怖嚎莉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沛豌,我是刑警寧澤趋箩,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站加派,受9級特大地震影響叫确,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜芍锦,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一竹勉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧娄琉,春花似錦次乓、人聲如沸吓歇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽城看。三九已至,卻和暖如春杏慰,著一層夾襖步出監(jiān)牢的瞬間测柠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工缘滥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鹃愤,地道東北人。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓完域,卻偏偏與公主長得像软吐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子吟税,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容