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
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.