Building Production Quality Apps on App Engine. Ken Ashcraft 5/29/2008

Similar documents
Chapter 19: Twitter in Twenty Minutes

App Engine Web App Framework

App Engine Web App Framework

Google & the Cloud. GData, Mashup Editor, AppEngine. Gregor Hohpe Software Engineer Google, Inc. All rights reserved,

webapp2 Documentation

Rapid Development with Django and App Engine. Guido van Rossum May 28, 2008

CS4HS Using Google App Engine. Michael Parker


Building Python web app on GAE

Hons. B.Sc. Degree in Software Engineering/Development. Web and Cloud Development

COMP1730/COMP6730 Programming for Scientists. Exceptions and exception handling

Introduction to Problem Solving and Programming in Python.

Installing and Running the Google App Engine On a Macintosh System

CSC 148 Lecture 3. Dynamic Typing, Scoping, and Namespaces. Recursion

Fundamentals of Programming (Python) Getting Started with Programming

ArcGIS Enterprise Portal for ArcGIS

Building Scalable Web Apps with Python and Google Cloud Platform. Dan Sanderson, April 2015

Course Structure of Python Training: UNIT - 1: COMPUTER FUNDAMENTALS. Computer Fundamentals. Installation of Development Tools:

Jaesun Han (NexR CEO & Founder)

Building Scalable Web Apps with Google App Engine. Brett Slatkin June 14, 2008

61A Lecture 2. Friday, August 28, 2015

Conditionals & Control Flow

Getting Started with Python

Viri. Remote execution of Python scripts. Every time you use Viri, God kills a sysadmin. Marc Garcia

Repetition Algorithms

COMP 204: Sets, Commenting & Exceptions

CS2021- Week 10 Models and Views. Model, View, Controller. Web Development Model, Views, Controller Templates Databases

Outline. A C++ Linked Structure Class A C++ Linked List C++ Linked Dynamic Memory Errors In-class work. 1 Chapter 11: C++ Linked Structures

learning objectives learn about variables, their types and their values learn about different number representations

Optimizing Your App Engine App

PROCE55 Mobile: Web API App. Web API.

Google GCP-Solution Architects Exam

Control Structures 1 / 17

What is an Exception? Exception Handling. What is an Exception? What is an Exception? test = [1,2,3] test[3]

Outline. Introduction Concepts and terminology The case for static typing. Implementing a static type system Basic typing relations Adding context

Scope & Symbol Table. l Most modern programming languages have some notion of scope.

CS 11 python track: lecture 2

Author Bob Ippolito Conference. PyObjC Hacking. PyCon DC, March 2005

Making the Move to Magento 2: Successful Use of the Data Migration Tool

Jython. An introduction by Thinh Le

Abstract Data Types Chapter 1

SELENIUM - REMOTE CONTROL

Not-So-Mini-Lecture 6. Modules & Scripts

Scaling App Engine Applications. Justin Haugh, Guido van Rossum May 10, 2011

Errors. And How to Handle Them

한재선 KAIST 정보미디어경영대학원겸직교수 & NexR 대표이사

App Engine: Datastore Introduction

Exceptions Programming 1 C# Programming. Rob Miles

Exceptions. Exceptions. Exceptional Circumstances 11/25/2013

Call: Hyperion Planning Course Content:35-40hours Course Outline Planning Overview

Play with Python: An intro to Data Science

CMSC 201 Fall 2016 Lab 09 Advanced Debugging

CIS192 Python Programming

CIS192 Python Programming

61A Lecture 2. Wednesday, September 4, 2013

CIS192 Python Programming

Functions, Scope & Arguments. HORT Lecture 12 Instructor: Kranthi Varala

Any other Projects or assignments the student may be working on this week:

Classification Using Genetic Programming. Patrick Kellogg General Assembly Data Science Course (8/23/15-11/12/15)

Exam 2, Form A CSE 231 Spring 2014 (1) DO NOT OPEN YOUR EXAM BOOKLET UNTIL YOU HAVE BEEN TOLD TO BEGIN.

Exam 2, Form B CSE 231 Spring 2014 (1) DO NOT OPEN YOUR EXAM BOOKLET UNTIL YOU HAVE BEEN TOLD TO BEGIN.

Introduction to Computer Programming for Non-Majors

CIS192 Python Programming

learning objectives learn about variables, their types and their values learn about different number representations

GIS 4653/5653: Spatial Programming and GIS. More Python: Statements, Types, Functions, Modules, Classes

Introduction to Computer Programming for Non-Majors

CS558 Programming Languages

Introduction to: Computers & Programming: Exception Handling

Flask Web Development Course Catalog

Date Version Revision

CSE450. Translation of Programming Languages. Lecture 11: Semantic Analysis: Types & Type Checking

CS558 Programming Languages

Continuous delivery of Java applications. Marek Kratky Principal Sales Consultant Oracle Cloud Platform. May, 2016

Protect your apps and your customers against application layer attacks

Python Essential Reference, Second Edition - Chapter 5: Control Flow Page 1 of 8

Unit 6 - Software Design and Development LESSON 4 DATA TYPES

Test #2 October 8, 2015

Introduction to Computer Programming for Non-Majors

Python The way of a program. Srinidhi H Asst Professor Dept of CSE, MSRIT

Alan Nichol Co-founder and CTO, Rasa

Curriculum Catalog

Getting the most out of Spring and App Engine!!

Lecture 1. basic Python programs, defining functions

Can it connect to database used for NEO reports?

PYTHON DATA SCIENCE TOOLBOX II. List comprehensions

IGL S AND MOUNT NS. Taking AKKA to Production

Developing with Google App Engine

Lab 2 Third Party API Integration, Cloud Deployment & Benchmarking

Introduction to PyObjC

DevOps Online Training

Alastair Burt Andreas Eisele Christian Federmann Torsten Marek Ulrich Schäfer. October 6th, Universität des Saarlandes. Introduction to Python

Microservices. SWE 432, Fall 2017 Design and Implementation of Software for the Web

CS Programming Languages: Python

Introduction to Computer Programming for Non-Majors

1 Lecture 6: Conditionals and Exceptions

7401ICT eservice Technology. (Some of) the actual examination questions will be more precise than these.

Internal Classes and Exceptions

Serverless and APIs: Rethinking Curriculum in Higher Education. Munir Mandviwalla and Jeremy Shafer Temple University

Extending Jython. with SIM, SPARQL and SQL

BEAMJIT, a Maze of Twisty Little Traces

Transcription:

Building Production Quality Apps on App Engine Ken Ashcraft 5/29/2008

Outline Writing code for production Testing performance Safe deployment after launch 3

Writing Code for Production

Writing Code for Production Errors happen movie = Movie() movie.title = self.request.get( title, None) movie.director = self.request.get( director, None) movie.put() 5

Writing Code for Production Errors happen movie = Movie() movie.title = self.request.get( title, None) movie.director = self.request.get( director, None) movie.put() Out-of-memory 5

Writing Code for Production Errors happen movie = Movie() movie.title = self.request.get( title, None) movie.director = self.request.get( director, None) movie.put() Out-of-memory DeadlineExceeded 5

Writing Code for Production Errors happen movie = Movie() movie.title = self.request.get( title, None) movie.director = self.request.get( director, None) movie.put() Out-of-memory DeadlineExceeded OverQuotaError 5

Writing Code for Production Errors happen movie = Movie() movie.title = self.request.get( title, None) movie.director = self.request.get( director, None) movie.put() Out-of-memory DeadlineExceeded OverQuotaError Server crash 5

Writing Code for Production Errors happen movie = Movie() movie.title = self.request.get( title, None) movie.director = self.request.get( director, None) movie.put() Out-of-memory DeadlineExceeded OverQuotaError Server crash Datastore crash 5

Writing Code for Production Errors happen movie = Movie() movie.title = self.request.get( title, None) movie.director = self.request.get( director, None) movie.put() Out-of-memory DeadlineExceeded OverQuotaError Server crash Datastore crash Identical entity already exists 5

Writing Code for Production Use logging for forensics import logging user = users.get_current_user() if user: q = db.gqlquery("select * FROM UserPrefs WHERE user = :1", user) results = q.fetch(2) if len(results) > 1: logging.error( Multiple UserPrefs for user %s", user) if len(results) == 0: logging.debug( Creating UserPrefs for user %s", user) userprefs = UserPrefs(user=user) userprefs.put() else: userprefs = results[0] else: logging.debug( Creating dummy UserPrefs for anonymous user") 6

Writing Code for Production Email upon exception 7

Writing Code for Production Email upon exception class BaseRequestHandler(webapp.RequestHandler): 7

Writing Code for Production Email upon exception class BaseRequestHandler(webapp.RequestHandler): def handle_exception(self, exception, debug_mode): 7

Writing Code for Production Email upon exception class BaseRequestHandler(webapp.RequestHandler): def handle_exception(self, exception, debug_mode): lines =.join(traceback.format_exception(*sys.exc_info ())) 7

Writing Code for Production Email upon exception class BaseRequestHandler(webapp.RequestHandler): def handle_exception(self, exception, debug_mode): lines =.join(traceback.format_exception(*sys.exc_info ())) logging.error(lines) 7

Writing Code for Production Email upon exception class BaseRequestHandler(webapp.RequestHandler): def handle_exception(self, exception, debug_mode): lines =.join(traceback.format_exception(*sys.exc_info ())) logging.error(lines) mail.send_mail_to_admins(sender= myapp-noreply@gmail.com, 7

Writing Code for Production Email upon exception class BaseRequestHandler(webapp.RequestHandler): def handle_exception(self, exception, debug_mode): lines =.join(traceback.format_exception(*sys.exc_info ())) logging.error(lines) mail.send_mail_to_admins(sender= myapp-noreply@gmail.com, subject= Caught Exception, 7

Writing Code for Production Email upon exception class BaseRequestHandler(webapp.RequestHandler): def handle_exception(self, exception, debug_mode): lines =.join(traceback.format_exception(*sys.exc_info ())) logging.error(lines) mail.send_mail_to_admins(sender= myapp-noreply@gmail.com, subject= Caught Exception, body=lines) 7

Writing Code for Production Email upon exception class BaseRequestHandler(webapp.RequestHandler): def handle_exception(self, exception, debug_mode): lines =.join(traceback.format_exception(*sys.exc_info ())) logging.error(lines) mail.send_mail_to_admins(sender= myapp-noreply@gmail.com, subject= Caught Exception, body=lines) template_values = {} 7

Writing Code for Production Email upon exception class BaseRequestHandler(webapp.RequestHandler): def handle_exception(self, exception, debug_mode): lines =.join(traceback.format_exception(*sys.exc_info ())) logging.error(lines) mail.send_mail_to_admins(sender= myapp-noreply@gmail.com, subject= Caught Exception, body=lines) template_values = {} if users.is_current_user_admin(): 7

Writing Code for Production Email upon exception class BaseRequestHandler(webapp.RequestHandler): def handle_exception(self, exception, debug_mode): lines =.join(traceback.format_exception(*sys.exc_info ())) logging.error(lines) mail.send_mail_to_admins(sender= myapp-noreply@gmail.com, subject= Caught Exception, body=lines) template_values = {} if users.is_current_user_admin(): template_values[ traceback ] = lines 7

Writing Code for Production Email upon exception class BaseRequestHandler(webapp.RequestHandler): def handle_exception(self, exception, debug_mode): lines =.join(traceback.format_exception(*sys.exc_info ())) logging.error(lines) mail.send_mail_to_admins(sender= myapp-noreply@gmail.com, subject= Caught Exception, body=lines) template_values = {} if users.is_current_user_admin(): template_values[ traceback ] = lines self.response.out.write(template.render( error.html, 7

Writing Code for Production Email upon exception class BaseRequestHandler(webapp.RequestHandler): def handle_exception(self, exception, debug_mode): lines =.join(traceback.format_exception(*sys.exc_info ())) logging.error(lines) mail.send_mail_to_admins(sender= myapp-noreply@gmail.com, subject= Caught Exception, body=lines) template_values = {} if users.is_current_user_admin(): template_values[ traceback ] = lines self.response.out.write(template.render( error.html, template_values)) 7

Writing Code for Production Using the Python profiler http://code.google.com/appengine/kb/commontasks.html#profiling 8

Writing Code for Production Using the Python profiler def real_main(): http://code.google.com/appengine/kb/commontasks.html#profiling 8

Writing Code for Production Using the Python profiler def real_main(): application = webapp.wsgiapplication([ http://code.google.com/appengine/kb/commontasks.html#profiling 8

Writing Code for Production Using the Python profiler def real_main(): application = webapp.wsgiapplication([ ('/(.*)', WikiPage), http://code.google.com/appengine/kb/commontasks.html#profiling 8

Writing Code for Production Using the Python profiler def real_main(): application = webapp.wsgiapplication([ ('/(.*)', WikiPage), ], debug=_debug) http://code.google.com/appengine/kb/commontasks.html#profiling 8

Writing Code for Production Using the Python profiler def real_main(): application = webapp.wsgiapplication([ ('/(.*)', WikiPage), ], debug=_debug) wsgiref.handlers.cgihandler().run(application) http://code.google.com/appengine/kb/commontasks.html#profiling 8

Writing Code for Production Using the Python profiler def real_main(): application = webapp.wsgiapplication([ ('/(.*)', WikiPage), ], debug=_debug) wsgiref.handlers.cgihandler().run(application) def profile_main(): http://code.google.com/appengine/kb/commontasks.html#profiling 8

Writing Code for Production Using the Python profiler def real_main(): application = webapp.wsgiapplication([ ('/(.*)', WikiPage), ], debug=_debug) wsgiref.handlers.cgihandler().run(application) def profile_main(): # Turn on profiling and run real_main() http://code.google.com/appengine/kb/commontasks.html#profiling 8

Writing Code for Production Using the Python profiler def real_main(): application = webapp.wsgiapplication([ ('/(.*)', WikiPage), ], debug=_debug) wsgiref.handlers.cgihandler().run(application) def profile_main(): # Turn on profiling and run real_main() http://code.google.com/appengine/kb/commontasks.html#profiling 8

Writing Code for Production Using the Python profiler def real_main(): application = webapp.wsgiapplication([ ('/(.*)', WikiPage), ], debug=_debug) wsgiref.handlers.cgihandler().run(application) def profile_main(): # Turn on profiling and run real_main() logging.info("profile data:\n%s", profile_data) http://code.google.com/appengine/kb/commontasks.html#profiling 8

Writing Code for Production Using the Python profiler def real_main(): application = webapp.wsgiapplication([ ('/(.*)', WikiPage), ], debug=_debug) wsgiref.handlers.cgihandler().run(application) def profile_main(): # Turn on profiling and run real_main() logging.info("profile data:\n%s", profile_data) def main(): http://code.google.com/appengine/kb/commontasks.html#profiling 8

Writing Code for Production Using the Python profiler def real_main(): application = webapp.wsgiapplication([ ('/(.*)', WikiPage), ], debug=_debug) wsgiref.handlers.cgihandler().run(application) def profile_main(): # Turn on profiling and run real_main() logging.info("profile data:\n%s", profile_data) def main(): if random.randint(0, 100) == 4: http://code.google.com/appengine/kb/commontasks.html#profiling 8

Writing Code for Production Using the Python profiler def real_main(): application = webapp.wsgiapplication([ ('/(.*)', WikiPage), ], debug=_debug) wsgiref.handlers.cgihandler().run(application) def profile_main(): # Turn on profiling and run real_main() logging.info("profile data:\n%s", profile_data) def main(): if random.randint(0, 100) == 4: profile_main() http://code.google.com/appengine/kb/commontasks.html#profiling 8

Writing Code for Production Using the Python profiler def real_main(): application = webapp.wsgiapplication([ ('/(.*)', WikiPage), ], debug=_debug) wsgiref.handlers.cgihandler().run(application) def profile_main(): # Turn on profiling and run real_main() logging.info("profile data:\n%s", profile_data) def main(): if random.randint(0, 100) == 4: profile_main() else: http://code.google.com/appengine/kb/commontasks.html#profiling 8

Writing Code for Production Using the Python profiler def real_main(): application = webapp.wsgiapplication([ ('/(.*)', WikiPage), ], debug=_debug) wsgiref.handlers.cgihandler().run(application) def profile_main(): # Turn on profiling and run real_main() logging.info("profile data:\n%s", profile_data) def main(): if random.randint(0, 100) == 4: profile_main() else: real_main() http://code.google.com/appengine/kb/commontasks.html#profiling 8

Writing Code for Production Errors happen! 9

Loadtests

Loadtests What not to do The dev_appserver is not designed for performance! 11

Loadtests What not to do 60 50 40 30 20 10 0 0 1 2 3 4 5 6 7 8 9 1011121314151617181920 12

The Request Path User App Engine Frontend App s Python Interpreter 13

The Request Path User App Engine Frontend App s Python Interpreter 13

The Request Path User User User App Engine Frontend App s Python Interpreter User User 13

The Request Path User User User App Engine Frontend App s Python Interpreter User User 13

The Request Path User User App s Python Interpreter User App Engine Frontend App s Python Interpreter User User App s Python Interpreter 13

Loadtests Good vs Bad 60 50 40 30 20 10 0 0 1 2 3 4 5 6 7 8 9 1011121314151617181920 14

Loadtests Realistic values 15

Loadtests Realistic values 50,000 users / day 15

Loadtests Realistic values 50,000 users / day 2 pageviews / user 15

Loadtests Realistic values 50,000 users / day 2 pageviews / user 100,000 pageviews / day 15

Loadtests Realistic values 50,000 users / day 2 pageviews / user 100,000 pageviews / day 5 requests / pageview 15

Loadtests Realistic values 50,000 users / day 2 pageviews / user 100,000 pageviews / day 5 requests / pageview 500,000 requests / day 15

Loadtests Realistic values 50,000 users / day 2 pageviews / user 100,000 pageviews / day 5 requests / pageview 500,000 requests / day 5.8 requests / second 15

Loadtests Good vs Bad 60 50 40 30 20 10 0 0 1 2 3 4 5 6 7 8 9 1011121314151617181920 16

Loadtests Good vs Bad 60 Qualities of a good load test: 50 40 30 20 10 0 0 1 2 3 4 5 6 7 8 9 1011121314151617181920 16

Loadtests Good vs Bad 60 50 40 Qualities of a good load test: Use production system (not dev_appserver) 30 20 10 0 0 1 2 3 4 5 6 7 8 9 1011121314151617181920 16

Loadtests Good vs Bad 60 50 40 Qualities of a good load test: Use production system (not dev_appserver) Gradual ramp up 30 20 10 0 0 1 2 3 4 5 6 7 8 9 1011121314151617181920 16

Loadtests Good vs Bad 60 50 40 30 Qualities of a good load test: Use production system (not dev_appserver) Gradual ramp up Sustained load 20 10 0 0 1 2 3 4 5 6 7 8 9 1011121314151617181920 16

Loadtests Good vs Bad 60 50 40 30 20 Qualities of a good load test: Use production system (not dev_appserver) Gradual ramp up Sustained load Realistic load 10 0 0 1 2 3 4 5 6 7 8 9 1011121314151617181920 16

Safe Deployment

How App Versioning Works http://wiki-io.appspot.com User App Engine Frontend Version 1.1 Datastore 18

How App Versioning Works http://wiki-io.appspot.com User App Engine Frontend Version 1.2 Datastore 19

How App Versioning Works http://wiki-io.appspot.com Version 1.1 User App Engine Frontend Datastore http://2.1.wiki-io.appspot.com Version 2.1 20

App Versioning Control the version with app.yaml application: wiki-io version: 5482 # Revision number runtime: python api_version: 1 Suggestion: Create a build script to populate version 21

How App Versioning Works http://wiki-io.appspot.com Version 1.1 User App Engine Frontend Datastore http://2.1.wiki-io.appspot.com Version 2.1 22

How App Versioning Works http://1.1.wiki-io.appspot.com Version 1.1 User App Engine Frontend Datastore http://wiki-io.appspot.com Version 2.1 23

Testing the Release http://<major>.<minor>.<app>.appspot.com Selenium: a test tool for web applications http://selenium.openqa.org Use the log viewer to look for errors 24

Feature Requests 25

Feature Requests A/B testing 25

Feature Requests A/B testing Integration with SVN 25

Feature Requests A/B testing Integration with SVN Edit running code 25

Summary 26

Summary Write code to handle errors Use logging and catch exceptions 26

Summary Write code to handle errors Use logging and catch exceptions Do realistic loadtests 26

Summary Write code to handle errors Use logging and catch exceptions Do realistic loadtests Use versions for safe deployment 26