Сельдерей и сигналы

У меня была функция вроде этого

def calculate(self, input):
    result = input * 2

    if result > 4:
        result_higher_then_four.send(result)

    return result

Где result_higher_then_four, очевидно, представляет сигнал.

Затем я представил сельдерей, и моя функция выглядела ниже, и я больше не получал сигнал. Я полагаю, что сигналы привязаны к каждому процессу, и поскольку сельдерей работает в другом процессе, это означает, что я не могу поймать сигнал в основном процессе. Должен ли я использовать thread_local, чтобы исправить это? Или я не вижу очевидного?

Спасибо

@task
def calculate(self, input):
    result = input * 2

    if result > 4:
        result_higher_then_four.send(result)

    return result

Ответ 1

Проблема заключается в том, что приемник сигнала не регистрируется. Работники сельдерея работают в своем собственном процессе, поэтому в этом процессе необходимо создавать сигнальные соединения. Если вы знаете, что они представляют или могут их обнаружить, вы можете зарегистрировать их во время инициализации задачи, используя эту технику.

Конечно, это устраняет некоторые преимущества использования сигналов в первую очередь, потому что вам нужно заранее знать соединения.

Одна идея - предположить, что приемники сигналов всегда будут регистрироваться в модуле модулей каждого приложения. В этом случае будут работать следующие.

class CalculateTask(celery.Task):

    def __init__(self):
        from django.conf import settings
        for app in settings.INSTALLED_APPS:
            app_models = '{}.{}'.format(app,'models') 
            __import__(app_models, globals=globals())                                 

    def run(self, input):
        result = input * 2
        if result > 4:
            result_higher_then_four.send(result)

        return result

Ответ 2

Вы можете использовать сигнал celeryd_init для инициализации ваших работников и сигналов http://celery.readthedocs.org/en/latest/userguide/signals.html#celeryd-init

Основываясь на том, что вы предоставили, я тестировал с помощью:

from celery.signals import celeryd_init
from celery.utils.dispatch import Signal

def process_result(result, *args, **kwargs):
    print "signals received: %s" % result

result_higher_then_four = Signal()

@celeryd_init.connect
def init_signals(*args, **kwargs):
    result_higher_then_four.connect(process_result)

@task(bind=True)
def calculate(self, input):
    result = input * 2

    if result > 4:
       result_higher_then_four.send(result=result, sender=self)

    return result

Ответ 3

Если я правильно понял, вы хотите, чтобы один и тот же процесс отправил ans, получил сигнал, который он отправил? если да, то почему бы не использовать:

os.kill(os.getpid(), signal.SIGUSER1)

и определить обработчик для SIGUSR1 соответственно?

Если вы хотите, чтобы другой процесс получил его, у вас должен быть свой pid в любом случае, чтобы отправлять ему сигналы, поэтому просто используйте ту же команду, которую я дал здесь с правильным pid, а не os.getpid(). Если я что-то пропустил?