Esteban Vargas
Esteban Vargas

Reputation: 594

Why is this simple Flask script taking so long to run?

It's just a script that sends a mail once a form is submitted:

@application.route('/contact', methods=['GET', 'POST'])
def send():
    if request.method == 'POST':
        first_name = request.form['first_name']
        last_name = request.form['last_name']
        email = request.form['email']
        msg = Message('Hey!', sender='[email protected]', recipients=['[email protected]'])
        msg.body = email + " " + first_name + " " + last_name + " "
        mail.send(msg)
        msg2 = Message('Hello', sender='[email protected]', recipients=[email])
        msg2.body = "Hi " + first_name + ". Thanks for requesting access to our beta. We'll contact you soon to schedule a call."
        mail.send(msg2)

        return render_template('contact.html')

    return render_template ('index.html')

Both emails get delivered, but it takes too long for the script to be processed, which is resulting in fewer signups. What's wrong?

Just in case, I'm hosting this Flask application on an Elastic Beanstalk instance.

Upvotes: 0

Views: 203

Answers (1)

SivolcC
SivolcC

Reputation: 3618

Sending email is an operation that does takes times. If you enable the logs, you can see that several calls are made. This is not related to AWS or to your server.

Sending emails should be an asynchronous task in your flask app.

There is many ways to do this. You could simply refactor your code and write a function with a @async decorator, flask mega tutorial details that quite well.

#[...other imports...]
from threading import Thread

def async(f):
    def wrapper(*args, **kwargs):
        thr = Thread(target=f, args=args, kwargs=kwargs)
        thr.start()
    return wrapper

@async
def send_async_email(app, msg):
    with app.app_context():
        mail.send(msg)

@application.route('/contact', methods=['GET', 'POST'])
def send():
    if request.method == 'POST':
        first_name = request.form['first_name']
        last_name = request.form['last_name']
        email = request.form['email']
        msg = Message('Hey!', sender='[email protected]', recipients=['[email protected]'])
        msg.body = email + " " + first_name + " " + last_name + " "
        send_async_email(application, msg)
        msg2 = Message('Hello', sender='[email protected]', recipients=[email])
        msg2.body = "Hi " + first_name + ". Thanks for requesting access to our beta. We'll contact you soon to schedule a call."
        send_async_email(application, msg)

        return render_template('contact.html')

    return render_template ('index.html')

Since you are running your app on AWS, you could also use SES instead of Flask-Mail.

Others solutions would be to use a message queue, like RabbitMQ, but that would involve writting lot more code.

All those solutions will make the email being sent in the background, alowing your flask app to return a response to the client without having to wait for the email being sent.

Upvotes: 1

Related Questions