14

This code is my celery worker script:

from app import celery, create_app
app = create_app('default')
app.app_context().push()

When I try to run the worker I will get into this error:

File "/home/vagrant/myproject/venv/app/mymail.py", line 29, in send_email_celery
    msg.html = render_template(template + '.html', **kwargs)
  File "/home/vagrant/myproject/venv/local/lib/python2.7/site-packages/flask/templating.py", line 126, in render_template
    ctx.app.update_template_context(context)
  File "/home/vagrant/myproject/venv/local/lib/python2.7/site-packages/flask/app.py", line 716, in update_template_context
    context.update(func())
TypeError: 'NoneType' object is not iterable

My question is how can I send the email task, when using a worker in celery.

mymail.py

from flask import current_app, render_template
from flask.ext.mail import Message
from . import mail, celery

@celery.task
def send_async_email_celery(msg):
    mail.send(msg)

def send_email_celery(to, subject, template, **kwargs):
    app = current_app._get_current_object()
    msg = Message(subject, sender=app.config['MAIL_SENDER'], recipients=[to])
    msg.html = render_template(template + '.html', **kwargs)
    send_async_email_celery.delay(msg)

__init__

...

def create_app(config_name):
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    config[config_name].init_app(app)

    bootstrap.init_app(app)
    mail.init_app(app)
    db.init_app(app)
    login_manager.init_app(app)
    celery.conf.update(app.config)

    redis_store.init_app(app)

    from .users import main as main_blueprint
    app.register_blueprint(main_blueprint)

    return app

Apparently there is some conflict between the blueprint and worker. Remove the blueprint is not an option, if possible, due the custom filters that I need to use in email template.

anvd
  • 3,997
  • 19
  • 65
  • 126
  • I don't follow the reasoning here. Do you want the celery worker to register a blueprint? Sounds backwards to me, I would expect a blueprint to register celery tasks, not the other way around. Could you maybe explain what the blueprint is supposed to do and what the celery worker is supposed to do? – Dag Høidahl Dec 08 '15 at 23:20
  • also, what's in your template? – user3012759 Dec 09 '15 at 10:05
  • @user3012759 even with an empty template (just for debugging), I will get the error. So the problem is not the template. – anvd Dec 09 '15 at 10:12

1 Answers1

10

Finally found what is the reason of the problem after some debug with this code.

I have a app_context_processor that will not return any result.

@mod.app_context_processor
def last_reputation_changes():
    if current_user:
        #code
        return dict(reputation='xxx')

When sending the email the current_user will need an else case to return something, since current_user from from flask.ext.login import current_user is not defined. Basically I only need something like this.

def last_reputation_changes():
    if current_user:
        #code
        return dict(reputation='xxx')
    else:
        return dict(reputation=None)

So the problem is not related with celery, but with the flask login integration.

anvd
  • 3,997
  • 19
  • 65
  • 126