antoinemartin / django-windows-tools

Django application providing management commands to host Django projects in Windows environments
BSD 2-Clause "Simplified" License
51 stars 13 forks source link

Celery: [ERROR/Process-1] Celery not Working #25

Open myusernamenone opened 6 years ago

myusernamenone commented 6 years ago

Problem:

celery ( use django-windows-tools) gets this task and displays that it was received in the log (service.log), but does not starting task.

Error service.log

[INFO/Process-1] Starting command : C:\Program Files (x86)\Python36-32\lib\site-packages\django_windows_tools\service.py celeryd -f C:\www\logs\celery.log -l info
[ERROR/Process-1] Process 'Worker-8' pid:10248 exited with 'exitcode 1'
[ERROR/Process-1] Process 'Worker-7' pid:10928 exited with 'exitcode 1'
[ERROR/Process-1] Process 'Worker-6' pid:7892 exited with 'exitcode 1'
[ERROR/Process-1] Process 'Worker-5' pid:8664 exited with 'exitcode 1'

technology stack:

Celery == 3.1.25 Python == 3.6.3 django-celery == 3.2.2 celery == 3.1.25 django-windows-tools == 0.2 django == 1.11 wfastcgi == 3.0.0

redis Windows Server 2016 Standard == 1607 (Build 14393.1198)

ini:

[services]
# Services to be run on all machines
run=celeryd
clean=C:\www\logs\celery.log

[BEATSERVER]
# There should be only one machine with the celerybeat service
run=celeryd celerybeat
clean=C:\www\logs\celerybeat.pid;C:\www\logs\beat.log;C:\www\logs\celery.log

[celeryd]
command=celeryd
parameters=-f C:\www\logs\celery.log -l info

[celerybeat]
command=celerybeat
parameters=-f C:\www\logs\beat.log -l info --pidfile=C:\www\logs\celerybeat.pid

[runserver]
# Runs the debug server and listen on port 8000
# This one is just an example to show that any manage command can be used
command=runserver
parameters=--noreload --insecure 0.0.0.0:8000

[log]
filename=C:\www\logs\service.log
level=INFO
myusernamenone commented 6 years ago

django - django_tests.zip log - logs.zip

mrbean-bremen commented 6 years ago

As I wrote in the compatibility notes, this combination has never been tested. Last time I used celery myself (about 3 or 4 years ago), I used Python 2.7, Django 1.6 and an older celery version. There seems to be a general problem with celery under Python 3.6 and current django versions. Sorry I can't help here - I may get around to try this out some time, but currently I don't have a suitable system, so this may take some time.

aspistrel commented 6 years ago

@myusernamenone @mrbean-bremen I have faced the same problem and seems like I've solved it in my case. Here are the details.

First I run it with debug option, like:

..\pythonservice.exe -debug <servicename>

And I got a traceback:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Users\<user>\Envs\<my_env>\lib\site-packages\billiard\forking.py", line 430, in main
    prepare(preparation_data)
  File "C:\Users\<user>\Envs\<my_env>\lib\site-packages\billiard\forking.py", line 557, in prepare
    file, path_name, etc = imp.find_module(main_name, dirs)
  File "C:\Users\<user>\Envs\<my_emv>\lib\imp.py", line 297, in find_module
    raise ImportError(_ERR_MSG.format(name), name=name)
ImportError: No module named 'pythonservice'

After that I looked into the django-windows-tools\service.py and found that code:

# Do the same monkey patching on billiard which is a fork of
# multiprocessing
try:
    import billiard.forking as billiard_forking
    main_path_key = 'main_path'
except ImportError:
    try:
        import billiard.spawn as billiard_forking
        main_path_key = 'init_main_from_path'

        billiard_old_get_preparation_data = billiard_forking.get_preparation_data

        def billiard_new_get_preparation_data(name):
            d = billiard_old_get_preparation_data(name)
            if main_path_key in d and d[main_path_key].lower().endswith('.exe'):
                # del d['main_path']
                d[main_path_key] = '__main__.py'
            return d

        billiard_forking.get_preparation_data = billiard_new_get_preparation_data
    except:
        pass

And I rewrote it into that:

# Do the same monkey patching on billiard which is a fork of
# multiprocessing
try:
    import billiard.forking as billiard_forking

    main_path_key = 'main_path'

except ImportError:
    try:
        import billiard.spawn as billiard_forking

        main_path_key = 'init_main_from_path'
    except:
        pass

try:
    billiard_old_get_preparation_data = billiard_forking.get_preparation_data

    def billiard_new_get_preparation_data(name):
        d = billiard_old_get_preparation_data(name)
        if main_path_key in d and d[main_path_key].lower().endswith('.exe'):
            # del d['main_path']
            d[main_path_key] = '__main__.py'
        return d

    billiard_forking.get_preparation_data = billiard_new_get_preparation_data
except:
    pass

And after that error has gone and now celery works fine.

So, actually, this code fixes the problem, I guess

            if main_path_key in d and d[main_path_key].lower().endswith('.exe'):
                # del d['main_path']
                d[main_path_key] = '__main__.py'

but for some reason it will run only if you had installed billiard 3.5 (which has billiard.spawn), but celery 3.1.25 comes with billiard 3.3 (which has billiard.forking) and this code will never be reached. I don't know if this change affects something else in a bad way, but I can say that it worked for me in this case.

mrbean-bremen commented 6 years ago

Thanks a lot for sharing that! I will have a closer look sometime later and check if this can be integrated.

mrbean-bremen commented 6 years ago

I pushed your change - it should not have any bad side affects, as far as I can see. Thanks again!

mrbean-bremen commented 6 years ago

FWIW, I published a new version with your fix on PyPi.

aspistrel commented 6 years ago

I'm glad I was able to help, thanks!