【问题标题】:Dynamically importing a module in a Celery task在 Celery 任务中动态导入模块
【发布时间】:2016-09-11 17:00:24
【问题描述】:

是否可以在 Celery 任务中动态导入模块?

例如,我的工作目录中有一个名为 hello.py 的模块:

$ cat hello.py 
def run():
    print('hello world')

我可以用importlib动态导入:

$ python3
Python 3.5.2 (default, Jul  5 2016, 12:43:10) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import importlib
>>> p = importlib.import_module('hello')
>>> p.run()
hello world

我想从 Celery 任务中执行与上述相同的操作:

@celery.task()
def exec_module(module, args={}):
    print('celery task running: %s' % (module))
    print(args)
    print(os.getcwd())
    print(os.listdir())

    module = importlib.import_module('hello')
    module.run()

任务运行时出现以下错误:

[2016-09-11 17:51:48,132: WARNING/MainProcess] celery@user-HP-EliteBook-840-G2 ready.
[2016-09-11 17:52:05,516: INFO/MainProcess] Received task: web.tasks.exec_module[f24e3d03-5a17-41dc-afa9-541c99b60a35]
[2016-09-11 17:52:05,518: WARNING/Worker-1] celery task running: example_module
[2016-09-11 17:52:05,518: WARNING/Worker-1] {'example_file': '/tmp/tmpo4ks9ql0.xml', 'example_string': 'asd'}
[2016-09-11 17:52:05,518: WARNING/Worker-1] /home/user/Learning/vision-boilerplate
[2016-09-11 17:52:05,518: WARNING/Worker-1] ['run.py', 'requirements.txt', 'gulpfile.js', 'tsconfig.json', 'typings.json', 'package.json', 'vision_modules', 'typings', 'web', 'config', 'hello.py', 'docker-compose.yml', 'ng', 'node_modules', 'Dockerfile']
[2016-09-11 17:52:05,523: ERROR/MainProcess] Task web.tasks.exec_module[f24e3d03-5a17-41dc-afa9-541c99b60a35] raised unexpected: ImportError("No module named 'hello'",)
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/celery/app/trace.py", line 240, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/home/user/Learning/vision-boilerplate/web/__init__.py", line 21, in __call__
    return TaskBase.__call__(self, *args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/celery/app/trace.py", line 438, in __protected_call__
    return self.run(*args, **kwargs)
  File "/home/user/Learning/vision-boilerplate/web/tasks.py", line 19, in exec_module
    module = importlib.import_module('hello')
  File "/usr/lib/python3.5/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 986, in _gcd_import
  File "<frozen importlib._bootstrap>", line 969, in _find_and_load
  File "<frozen importlib._bootstrap>", line 956, in _find_and_load_unlocked
ImportError: No module named 'hello'

print(os.listdir()) 的输出(上面调试输出中的第 6 行)可以看出,我们肯定在正确的目录中,hello.py 就在那儿。

是否可以从 Celery 任务中动态导入模块?

【问题讨论】:

    标签: python celery python-importlib


    【解决方案1】:

    2018-05-23 更新:

    在 celery 中,任务由工人消耗。默认情况下,多处理用于执行任务的并发执行。

    worker调用task函数时,我们当前的工作目录(os.getcwd())不在sys.path,所以找不到模块名。

    问题的根源可能是:Celery 启动工作进程时,没有复制当前进程的信息。


    是否可以在 Celery 任务中动态导入模块?

    是的。因为我已经做到了。 当模块为单个且不属于任何包时,应将模块所在目录添加到sys路径中。

    sys.path.append('模块路径')

    例如:

    import importlib
    import os
    import sys
    import celery
    from demo import celeryconfig
    
    # add your path to the sys path
    sys.path.append(os.getcwd())
    
    app = celery.Celery('tasks',)
    app.config_from_object(celeryconfig)
    
    
    @celery.task()
    def exec_module(module, args={}):
        print('celery task running: %s' % (module))
        print(args)
        print(os.getcwd())
        print(os.listdir())
    
        module = importlib.import_module('hello')
        module.run()
    

    希望对您有所帮助。谢谢

    【讨论】:

      猜你喜欢
      • 2012-08-26
      • 2013-10-02
      • 2017-01-22
      • 2016-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-09
      相关资源
      最近更新 更多