Shopify doesn't stop sending webhook to Flask app

Issue

I have a Flask app that listens to incoming Shopify webhooks, does something, and responds with 200. However, Shopify keeps sending the webhook as if my app responded with something other than 200.

When I simulate this with curl:

curl -H "Content-Type: application/json" -D /tmp/dump.log -X POST -d @<valid json> <my server>

the response headers are:

HTTP/1.1 100 Continue

HTTP/1.1 200 OK
Date: Thu, 16 Apr 2015 09:25:23 GMT
Server: Apache/2.4.7 (Ubuntu)
Content-Length: 0
Content-Type: text/html; charset=utf-8

I believe that the first 100 Continue is what’s making Shopify think my app failed. I get the same response on my local instance as well as on production.

What is going on and how can I fix it?

EDIT

Here’s the python code to process the request

import json
from flask_mail import Mail, Message
from pyPdf import PdfFileWriter, PdfFileReader
from flask import Flask
from certificate import Certificate
from flask import request
from purchase import Purchase
from stars import Stars

app = Flask(__name__)
app.config.from_envvar('NAMESTAR_SETTINGS')
app.config["MAIL_SERVER"] = 'smtp.sendgrid.net'
app.config["MAIL_PORT"] = 587
app.config["MAIL_USERNAME"] = app.config.get('EMAIL_LOGIN')
app.config["MAIL_PASSWORD"] = app.config.get('EMAIL_PASSWORD')
app.config["MAIL_DEFAULT_SENDER"] = app.config.get('SENDER')
app.config["PATH"] = app.config.get('PATH')
ADMINS = app.config.get('ADMINS')
mail = Mail(app)


def get_request():
    if request.args.get('hyg') is not None:
        return int(request.args.get('hyg'))
    else:
        return request.data


#returns an instance of Purchase class based on the request
def get_purchase():    
    pass


#creates and saves a PDF created with reportlab
def generate_certificate(purchase):
    pass


#sends the generated PDF to the recipient    
def send_email(certificate_path, recipient, name=""):
    msg = Message("Message", recipients=[recipient])
    with app.open_resource(certificate_path) as fp:
        msg.attach("certificate.pdf", "application/pdf", fp.read())
    f = open(app.config.get('PATH') + "/email_templates/certificate", "r")
    html = f.read()
    msg.html = html % (name)
    mail.send(msg)


@app.route('/', methods=['GET', 'POST'])
def generate():
    try:
        purchase = get_purchase()        
        certificate_path = generate_certificate(purchase)
        send_email(certificate_path, purchase.customer_email(), name=purchase.customer_name())        
    except Exception as e:        
        raise

    return ('', 200)


if __name__ == '__main__':
    app.debug = False
    app.run(debug=False)

The server is Apache, here’s the virtual host settings for the app

<VirtualHost *:80>
    DocumentRoot /var/www/namestar/current   
    WSGIDaemonProcess namestar user=www-data group=www-data threads=5
    WSGIScriptAlias / /var/www/namestar/current/namestar.wsgi    
    <Directory /var/www/namestar/current>
        WSGIScriptReloading On
        WSGIProcessGroup namestar
        WSGIApplicationGroup %{GLOBAL}
        Order deny,allow
        Allow from all
    </Directory>    
    SetEnv NAMESTAR_SETTINGS="/var/www/namestar/current/config/production.cfg"   
</VirtualHost>

Solution

Shopify said that the requests were timing out. Indeed, the processing took between 10-20 seconds so it makes sense. I moved the bulk of the execution to it’s own thread:

threading.Thread(target=generate, args=[purchase]).start()

and all is working as expected.

Answered By – Michal Holub

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published