SlideShare a Scribd company logo
1 of 40
Download to read offline
PyCon6 Apr2015, Florence, Italy
Art & Music VS AppEngine
Thomas Alisi, Solution Architect
@grudelsud @stinkdigital
photo courtesy of https://www.flickr.com/photos/8064990@N08/
See our 2015 showreel
Stinkdigital is an interactive production company,
working with clients and advertising agencies
worldwide.
Our services include creative concepting, design
and high-end execution. We create everything from
live-action films and websites, through to mobile
apps and installations.
Does this number look familiar to you?
86,400
Does this number look familiar to you?
86,400
= 60’’ x 60’ x 24h[number of seconds in 1 day]
What about this one?
31,536,000
What about this one?
31,536,000
= 86,400’’ x 365d[number of seconds in 1 year]
OK, now try and guess the last one
252,000,000
OK, now try and guess the last one
252,000,000
= 31.5M’’ x 8y[number of seconds in 8 years]
but also…
252,000,000
= 36M x 7’’[7 seconds saved for each of the 36M visits
we had during the first 6 months on DevArt]
How did we do it?
1. Google App Engine (GAE) and AngularJS
2. data structures
3. assets management
4. load testing
5. GAE benchmarking tool and task inspector
6. GAE asynchronous API
Revolutions in Sound - RedBull, Google+
http://archive.revolutionsinsound.com/
DevArt - Google CL
https://devart.withgoogle.com/
Inside Abbey Road - Google CL
https://insideabbeyroad.withgoogle.com/
1. Google App Engine (GAE) and AngularJS
2. data structures
3. assets management
4. load testing
5. GAE benchmarking tool and task inspector
6. GAE asynchronous API
- Grunt, Gulp, Browserify, Webpack… AAARGH!
- we like vanilla JS and have been fan of Gulp 

(at least over the past 10 minutes…)
- we (I) tend to use a super simple Gulp-Browserify-
AngularJS boilerplate 

https://github.com/grudelsud/angularjs-gulp-browserify-
boilerplate
- but there are other good examples too

e.g. https://github.com/unit9/coffee-bone
divide et impera
- GAE is not opinionated (which is good)
- default webapp2 shipped with GAE is really super simple
(a bit too simple…)
- Flask is OK and does not have preferences for a specific
ORM (which is great)
- don’t use Django on GAE unless you really want to 

(e.g. use legacy modules or deploy something really
quick)
class Jsonifiable(ndb.Model):
def from_dict(cls, dict):
pass
def to_dict(self, async=False):
pass
def resolve_future_blobs(cls, async_blobs):
pass
class JsonRestHandler(webapp2.RequestHandler):
JSON_MIMETYPE = "application/json"
def write(self, data):
self.response.out.write(data)
def send_success(self, obj=None, cache_expiry=None):
self.response.headers["Content-Type"] = self.JSON_MIMETYPE
self.write(json.dumps(obj, cls=JsonifiableEncoder))
webapp2 bespoke REST micro-framework
asynchronous conversion
bespoke encoder
basic permission check (skipped here)
extend ndb.Model
extend webapp2.RequestHandler
kibble_authenticator = ModelAuthenticatior()
admin = kibble.Kibble(
'admin',
__name__,
kibble_authenticator,
label='Admin',
static_url_path='/kibble/static',
default_gcs_bucket=app_identity.get_default_gcs_bucket_name(),
)
security_headers.apply(app)
class CustomJsonEncoder(flask.json.JSONEncoder):
def default(self, obj):
try:
if isinstance(obj, blobstore.BlobKey):
return str(obj)
if isinstance(obj, fields.Vertex):
return [obj.x, obj.y, obj.z]
if isinstance(obj, GCSFile):
return obj.cloudstore_url
if isinstance(obj, ndb.Key):
return obj.flat()
except TypeError:
pass
return super(CustomJsonEncoder, self).default(obj)
app = flask.Flask(__name__, template_folder='../templates')
app.json_encoder = CustomJsonEncoder
admin.autodiscover(paths=['admin'])
app.register_blueprint(admin, url_prefix='/admin')
Flask Blueprints and GAE
https://github.com/xlevus/flask-kibble
1. Google App Engine (GAE) and AngularJS
2. data structures
3. assets management
4. load testing
5. GAE benchmarking tool and task inspector
6. GAE asynchronous API
this always seems a good way to start
class ClubNight(BaseModel):
name = ndb.StringProperty()
content = ContentProperty(ndb.TextProperty)
blob_key_logo = ContentProperty(ndb.BlobKeyProperty)
genre = ndb.KeyProperty(kind=’Genre’)
website = ContentProperty(ndb.StringProperty)
address = ContentProperty(ndb.TextProperty)
location = ContentProperty(ndb.GeoPtProperty)
class Connection(ndb.Model):
from_key = ndb.KeyProperty()
to_key = ndb.KeyProperty()
abstraction
class ClubNight(BaseModel):
name = ndb.StringProperty()
content = ContentProperty(ndb.TextProperty)
blob_key_logo = ContentProperty(ndb.BlobKeyProperty)
genre = ndb.KeyProperty(kind=’Genre’)
website = ContentProperty(ndb.StringProperty)
address = ContentProperty(ndb.TextProperty)
location = ContentProperty(ndb.GeoPtProperty)
class Connection(ndb.Model):
from_key = ndb.KeyProperty()
to_key = ndb.KeyProperty()
to_name = ndb.StringProperty()
to_kind = ndb.StringProperty()
to_slug = ndb.StringProperty()
to_genre_colour = ndb.StringProperty()
to_image = ndb.BlobKeyProperty()
to_popularity = ndb.IntegerProperty()
is_published = ndb.BooleanProperty()
is_public = ndb.BooleanProperty(default=False)
is_featured = ndb.BooleanProperty(default=False)
reality
class Vertex(namedtuple('Vertex', ['x', 'y', 'z'])):
def __json__(self):
return json.dumps(self)
def __str__(self):
return 'x={0.x:.2f}, y={0.y:.2f}, z={0.z:.2f}'.format(self)
class VertexProperty(ndb.StringProperty):
# Dummy XYZ field, used to quickly add validation through
# admin.base.ModelConverter
def _validate(self, value):
if not isinstance(value, (tuple, Vertex)):
raise TypeError("Expected Vertex got %r" % repr(value))
if len(value) != 3:
raise TypeError("Expected 3-tuple/Vertex, got %r" % repr(value))
def _to_base_type(self, value):
return "%s,%s,%s" % value
def _from_base_type(self, value):
if value:
return Vertex(*[float(x) for x in value.split(",")])
return None
finding the sweet spot
1. Google App Engine (GAE) and AngularJS
2. data structures
3. assets management
4. load testing
5. GAE benchmarking tool and task inspector
6. GAE asynchronous API
The get_serving_url() method allows you to generate a stable, dedicated URL for
serving web-suitable image thumbnails. You simply store a single copy of your
original image in Blobstore, and then request a high-performance per-image URL.
[https://cloud.google.com/appengine/docs/python/images/]
ex.
// Resize the image to 32 pixels (aspect-ratio preserved)
http://your_app_id.appspot.com/randomStringImageId=s32
// Crop the image to 32 pixels
http://your_app_id.appspot.com/randomStringImageId=s32-c
Due diligence
=s500 =s100
- success == sleepless_nights (not for me! :P)
- PR scheduled on all major funnels:
- Google homepage
- Youtube homepage
- all major blogs (the verge, wired, etc.)
- London silicon roundabout
- 1.2M unique visits, 10M views during the FIRST 48H
si vis pacem, para bellum
from admin.publish_pipeline import Publish
rec = urlmap.PublishRecord.new()
p = Publish('admin.web.app', version=rec.key.id())
p.start()
[…]
class Publish(Pipeline):
"""
Root Pipeline. Creates a :py:class:`common.models.urlmap.PublishRecord` for
the pipeline, and spawns children.
On completion, sets publish record to completed.
"""
def run(self, app, locales=None, version=None):
rec = urlmap.PublishRecord.get_by_id(version)
rec.pipeline_id = self.root_pipeline_id
rec.put()
urlmaps = yield URLMaps(version)
with After(urlmaps):
static = yield WriteStaticFiles.pipeline(app, version)
sitemap = yield PublishSitemap(app, version)
short_urls = yield CreateShortUrls.pipeline(app, version)
with After(static, sitemap, short_urls):
json = yield PublishJSON(app, version)
with After(json):
yield CleanShortUrls(app, version)
yield Cleanup.pipeline()
static publishing pipeline
https://github.com/GoogleCloudPlatform/appengine-mapreduce/
create the pipeline and run process
extend mapreduce pipeline
spawn separate generators
1. Google App Engine (GAE) and AngularJS
2. data structures
3. assets management
4. load testing
5. GAE benchmarking tool and task inspector
6. GAE asynchronous API
GAE docs are rubbish! :) i.e. read it, then forget it:
https://cloud.google.com/appengine/articles/load_test
3rd party services are OK, but run your own if you can
create a meaningful simulation of users’ behaviour
hit it as hard as you can, but don’t forget your wallet!
class ApiNav(TaskSet):
@task(1)
def api_global(self):
self.client.get('/api/global?locale=%s' % langs[random.randint(0, len(langs)-1)], **kwargs)
@task(1)
def api_user(self):
self.client.get('/api/user', **kwargs)
@task(4)
def api_gallery(self):
self.client.get('/api/gallery?i=0&l=15', **kwargs)
@task(8)
def api_search(self):
self.client.get('/api/gallery?i=0&l=15&q=%s' % terms[random.randint(0, len(terms)-1)], **kwargs)
@task(6)
def api_feeling_lucky(self):
self.client.get('/api/page/feeling_lucky', **kwargs)
@task(2)
def api_big_gallery(self):
self.client.get('/api/gallery?i=0&l=30', **kwargs)
@task(2)
def api_featured(self):
self.client.get('/api/gallery?i=0&l=15&t=featured', **kwargs)
class MyLocust(HttpLocust):
host = 'https://sd-goog-devart.appspot.com'
task_set = ApiNav
min_wait = 5000
max_wait = 15000
locust
init data
gallery
random search
random project page
categorized views
- approximately 5000 concurrent user hitting the backend
API with a "casual navigation" simulation from different
location (London, New York, AWS data centre in Ireland)
- 85 running instances (class F2) at peak
- no errors reported other than random https sockets
timeout
- average response times
- < 2s for gallery content navigation
- < 1s for singe project page navitation
- < 3s for static contend (loaded just once)
1. Google App Engine (GAE) and AngularJS
2. data structures
3. assets management
4. load testing
5. GAE benchmarking tool and task inspector
6. GAE asynchronous API
1. Google App Engine (GAE) and AngularJS
2. data structures
3. assets management
4. load testing
5. GAE benchmarking tool and task inspector
6. GAE asynchronous API
@classmethod
def fix_dict(cls, dict, async=False):
async_blobs = []
def _fix_dict(k, v):
# blob
if isinstance(v, blobstore.BlobKey):
try:
# create futures and put them apart, we'll resolve these later
output = {'key': str(v), 'url': '', 'rpc': images.get_serving_url_async(v, secure_url=True)}
async_blobs.append(output)
return output
except BaseException as e:
# logging.warn('error while fetching serving url for [%s] maybe using corrupted image?' % (v,))
return None
for k, v in dict.iteritems():
dict[k] = _fix_dict(k, v)
if async is True:
return dict, async_blobs
else:
cls.resolve_future_blobs(async_blobs)
return dict
@classmethod
def resolve_future_blobs(cls, async_blobs):
# resolve futures
for blob in async_blobs:
try:
blob['url'] = blob['rpc'].get_result()
except BaseException:
blob['url'] = ''
del(blob['rpc'])
get_serving_url_async
1. get async url
3. get real url
2. resolve future blobs
Thanks!
uh, just few notes:
1. we are hiring! check www.stinkdigital.com/careers and send us your CV -
careers@stinkdigital.com
2. we organise a Meetup in London with UNIT9 and B-Reel, get in touch!
tomalisi@stinkdigital.com
3. www.slideshare.net/grudelsud

More Related Content

What's hot

Get started with YUI
Get started with YUIGet started with YUI
Get started with YUI
Adam Lu
 
Hey, I just met AngularJS, and this is crazy, so here’s my JavaScript, let’s ...
Hey, I just met AngularJS, and this is crazy, so here’s my JavaScript, let’s ...Hey, I just met AngularJS, and this is crazy, so here’s my JavaScript, let’s ...
Hey, I just met AngularJS, and this is crazy, so here’s my JavaScript, let’s ...
Alessandro Nadalin
 

What's hot (18)

Android Sliding Menu dengan Navigation Drawer
Android Sliding Menu dengan Navigation DrawerAndroid Sliding Menu dengan Navigation Drawer
Android Sliding Menu dengan Navigation Drawer
 
droidparts
droidpartsdroidparts
droidparts
 
Integrating React.js with PHP projects
Integrating React.js with PHP projectsIntegrating React.js with PHP projects
Integrating React.js with PHP projects
 
Get started with YUI
Get started with YUIGet started with YUI
Get started with YUI
 
Scriptaculous
ScriptaculousScriptaculous
Scriptaculous
 
Ultimate Introduction To AngularJS
Ultimate Introduction To AngularJSUltimate Introduction To AngularJS
Ultimate Introduction To AngularJS
 
Everything You (N)ever Wanted to Know about Testing View Controllers
Everything You (N)ever Wanted to Know about Testing View ControllersEverything You (N)ever Wanted to Know about Testing View Controllers
Everything You (N)ever Wanted to Know about Testing View Controllers
 
Android Wear Essentials
Android Wear EssentialsAndroid Wear Essentials
Android Wear Essentials
 
Hey, I just met AngularJS, and this is crazy, so here’s my JavaScript, let’s ...
Hey, I just met AngularJS, and this is crazy, so here’s my JavaScript, let’s ...Hey, I just met AngularJS, and this is crazy, so here’s my JavaScript, let’s ...
Hey, I just met AngularJS, and this is crazy, so here’s my JavaScript, let’s ...
 
Making Ajax Sexy, JSConf 2010
Making Ajax Sexy, JSConf 2010Making Ajax Sexy, JSConf 2010
Making Ajax Sexy, JSConf 2010
 
Making Ajax Sexy, JSConf 2010
Making Ajax Sexy, JSConf 2010Making Ajax Sexy, JSConf 2010
Making Ajax Sexy, JSConf 2010
 
Good karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with KarmaGood karma: UX Patterns and Unit Testing in Angular with Karma
Good karma: UX Patterns and Unit Testing in Angular with Karma
 
Primer vistazo al computer vision | 4Sessions Feb17
Primer vistazo al computer vision | 4Sessions Feb17Primer vistazo al computer vision | 4Sessions Feb17
Primer vistazo al computer vision | 4Sessions Feb17
 
Android basic 4 Navigation Drawer
Android basic 4 Navigation DrawerAndroid basic 4 Navigation Drawer
Android basic 4 Navigation Drawer
 
Introducing Vuex in your project
Introducing Vuex in your projectIntroducing Vuex in your project
Introducing Vuex in your project
 
Architecture for scalable Angular applications
Architecture for scalable Angular applicationsArchitecture for scalable Angular applications
Architecture for scalable Angular applications
 
2 years of angular: lessons learned
2 years of angular: lessons learned2 years of angular: lessons learned
2 years of angular: lessons learned
 
Architecture for scalable Angular applications (with introduction and extende...
Architecture for scalable Angular applications (with introduction and extende...Architecture for scalable Angular applications (with introduction and extende...
Architecture for scalable Angular applications (with introduction and extende...
 

Similar to Art & music vs Google App Engine

WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
Fabio Franzini
 
SharePoint Framework, Angular and Azure Functions
SharePoint Framework, Angular and Azure FunctionsSharePoint Framework, Angular and Azure Functions
SharePoint Framework, Angular and Azure Functions
Sébastien Levert
 

Similar to Art & music vs Google App Engine (20)

Performance and Optmization - a technical talk at Frontend London
Performance and Optmization - a technical talk at Frontend LondonPerformance and Optmization - a technical talk at Frontend London
Performance and Optmization - a technical talk at Frontend London
 
WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...WebNet Conference 2012 - Designing complex applications using html5 and knock...
WebNet Conference 2012 - Designing complex applications using html5 and knock...
 
AngularJS and SPA
AngularJS and SPAAngularJS and SPA
AngularJS and SPA
 
The Theory Of The Dom
The Theory Of The DomThe Theory Of The Dom
The Theory Of The Dom
 
MLSEV Virtual. From my First BigML Project to Production
MLSEV Virtual. From my First BigML Project to ProductionMLSEV Virtual. From my First BigML Project to Production
MLSEV Virtual. From my First BigML Project to Production
 
The Web on OSGi: Here's How
The Web on OSGi: Here's HowThe Web on OSGi: Here's How
The Web on OSGi: Here's How
 
WebGL: GPU acceleration for the open web
WebGL: GPU acceleration for the open webWebGL: GPU acceleration for the open web
WebGL: GPU acceleration for the open web
 
Professional JavaScript: AntiPatterns
Professional JavaScript: AntiPatternsProfessional JavaScript: AntiPatterns
Professional JavaScript: AntiPatterns
 
Viking academy backbone.js
Viking academy  backbone.jsViking academy  backbone.js
Viking academy backbone.js
 
JBUG 11 - Django-The Web Framework For Perfectionists With Deadlines
JBUG 11 - Django-The Web Framework For Perfectionists With DeadlinesJBUG 11 - Django-The Web Framework For Perfectionists With Deadlines
JBUG 11 - Django-The Web Framework For Perfectionists With Deadlines
 
Django tricks (2)
Django tricks (2)Django tricks (2)
Django tricks (2)
 
End-to-end testing with geb
End-to-end testing with gebEnd-to-end testing with geb
End-to-end testing with geb
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to java
 
AngularJS with TypeScript and Windows Azure Mobile Services
AngularJS with TypeScript and Windows Azure Mobile ServicesAngularJS with TypeScript and Windows Azure Mobile Services
AngularJS with TypeScript and Windows Azure Mobile Services
 
Data visualization in python/Django
Data visualization in python/DjangoData visualization in python/Django
Data visualization in python/Django
 
Viktor Tsykunov: Azure Machine Learning Service
Viktor Tsykunov: Azure Machine Learning ServiceViktor Tsykunov: Azure Machine Learning Service
Viktor Tsykunov: Azure Machine Learning Service
 
SCALA - Functional domain
SCALA -  Functional domainSCALA -  Functional domain
SCALA - Functional domain
 
Designing REST API automation tests in Kotlin
Designing REST API automation tests in KotlinDesigning REST API automation tests in Kotlin
Designing REST API automation tests in Kotlin
 
Javascript first-class citizenery
Javascript first-class citizeneryJavascript first-class citizenery
Javascript first-class citizenery
 
SharePoint Framework, Angular and Azure Functions
SharePoint Framework, Angular and Azure FunctionsSharePoint Framework, Angular and Azure Functions
SharePoint Framework, Angular and Azure Functions
 

Recently uploaded

Rohini Sector 22 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
Rohini Sector 22 Call Girls Delhi 9999965857 @Sabina Saikh No AdvanceRohini Sector 22 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
Rohini Sector 22 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
Call Girls In Delhi Whatsup 9873940964 Enjoy Unlimited Pleasure
 
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝
soniya singh
 
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
soniya singh
 
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
Call Girls In Delhi Whatsup 9873940964 Enjoy Unlimited Pleasure
 
Hot Service (+9316020077 ) Goa Call Girls Real Photos and Genuine Service
Hot Service (+9316020077 ) Goa  Call Girls Real Photos and Genuine ServiceHot Service (+9316020077 ) Goa  Call Girls Real Photos and Genuine Service
Hot Service (+9316020077 ) Goa Call Girls Real Photos and Genuine Service
sexy call girls service in goa
 
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRLLucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
imonikaupta
 
Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝
soniya singh
 

Recently uploaded (20)

Rohini Sector 22 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
Rohini Sector 22 Call Girls Delhi 9999965857 @Sabina Saikh No AdvanceRohini Sector 22 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
Rohini Sector 22 Call Girls Delhi 9999965857 @Sabina Saikh No Advance
 
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Sukhdev Vihar Delhi 💯Call Us 🔝8264348440🔝
 
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Defence Colony Delhi 💯Call Us 🔝8264348440🔝
 
Pune Airport ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready...
Pune Airport ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready...Pune Airport ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready...
Pune Airport ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready...
 
VIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call Girl
VIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call GirlVIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call Girl
VIP 7001035870 Find & Meet Hyderabad Call Girls LB Nagar high-profile Call Girl
 
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night StandHot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
Hot Call Girls |Delhi |Hauz Khas ☎ 9711199171 Book Your One night Stand
 
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
'Future Evolution of the Internet' delivered by Geoff Huston at Everything Op...
 
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
Dwarka Sector 26 Call Girls | Delhi | 9999965857 🫦 Vanshika Verma More Our Se...
 
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
✂️ 👅 Independent Andheri Escorts With Room Vashi Call Girls 💃 9004004663
 
Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Green Park Escort Service Delhi N.C.R.
 
@9999965857 🫦 Sexy Desi Call Girls Laxmi Nagar 💓 High Profile Escorts Delhi 🫶
@9999965857 🫦 Sexy Desi Call Girls Laxmi Nagar 💓 High Profile Escorts Delhi 🫶@9999965857 🫦 Sexy Desi Call Girls Laxmi Nagar 💓 High Profile Escorts Delhi 🫶
@9999965857 🫦 Sexy Desi Call Girls Laxmi Nagar 💓 High Profile Escorts Delhi 🫶
 
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
𓀤Call On 7877925207 𓀤 Ahmedguda Call Girls Hot Model With Sexy Bhabi Ready Fo...
 
Hot Service (+9316020077 ) Goa Call Girls Real Photos and Genuine Service
Hot Service (+9316020077 ) Goa  Call Girls Real Photos and Genuine ServiceHot Service (+9316020077 ) Goa  Call Girls Real Photos and Genuine Service
Hot Service (+9316020077 ) Goa Call Girls Real Photos and Genuine Service
 
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRLLucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
 
GDG Cloud Southlake 32: Kyle Hettinger: Demystifying the Dark Web
GDG Cloud Southlake 32: Kyle Hettinger: Demystifying the Dark WebGDG Cloud Southlake 32: Kyle Hettinger: Demystifying the Dark Web
GDG Cloud Southlake 32: Kyle Hettinger: Demystifying the Dark Web
 
Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$
Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$
Call Girls Dubai Prolapsed O525547819 Call Girls In Dubai Princes$
 
DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024
DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024
DDoS In Oceania and the Pacific, presented by Dave Phelan at NZNOG 2024
 
Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝
Call Girls In Model Towh Delhi 💯Call Us 🔝8264348440🔝
 
Networking in the Penumbra presented by Geoff Huston at NZNOG
Networking in the Penumbra presented by Geoff Huston at NZNOGNetworking in the Penumbra presented by Geoff Huston at NZNOG
Networking in the Penumbra presented by Geoff Huston at NZNOG
 
All Time Service Available Call Girls Mg Road 👌 ⏭️ 6378878445
All Time Service Available Call Girls Mg Road 👌 ⏭️ 6378878445All Time Service Available Call Girls Mg Road 👌 ⏭️ 6378878445
All Time Service Available Call Girls Mg Road 👌 ⏭️ 6378878445
 

Art & music vs Google App Engine

  • 1. PyCon6 Apr2015, Florence, Italy Art & Music VS AppEngine Thomas Alisi, Solution Architect @grudelsud @stinkdigital photo courtesy of https://www.flickr.com/photos/8064990@N08/
  • 2. See our 2015 showreel Stinkdigital is an interactive production company, working with clients and advertising agencies worldwide. Our services include creative concepting, design and high-end execution. We create everything from live-action films and websites, through to mobile apps and installations.
  • 3. Does this number look familiar to you? 86,400
  • 4. Does this number look familiar to you? 86,400 = 60’’ x 60’ x 24h[number of seconds in 1 day]
  • 5. What about this one? 31,536,000
  • 6. What about this one? 31,536,000 = 86,400’’ x 365d[number of seconds in 1 year]
  • 7. OK, now try and guess the last one 252,000,000
  • 8. OK, now try and guess the last one 252,000,000 = 31.5M’’ x 8y[number of seconds in 8 years]
  • 9. but also… 252,000,000 = 36M x 7’’[7 seconds saved for each of the 36M visits we had during the first 6 months on DevArt]
  • 10. How did we do it? 1. Google App Engine (GAE) and AngularJS 2. data structures 3. assets management 4. load testing 5. GAE benchmarking tool and task inspector 6. GAE asynchronous API
  • 11. Revolutions in Sound - RedBull, Google+ http://archive.revolutionsinsound.com/ DevArt - Google CL https://devart.withgoogle.com/ Inside Abbey Road - Google CL https://insideabbeyroad.withgoogle.com/
  • 12.
  • 13. 1. Google App Engine (GAE) and AngularJS 2. data structures 3. assets management 4. load testing 5. GAE benchmarking tool and task inspector 6. GAE asynchronous API
  • 14. - Grunt, Gulp, Browserify, Webpack… AAARGH! - we like vanilla JS and have been fan of Gulp 
 (at least over the past 10 minutes…) - we (I) tend to use a super simple Gulp-Browserify- AngularJS boilerplate 
 https://github.com/grudelsud/angularjs-gulp-browserify- boilerplate - but there are other good examples too
 e.g. https://github.com/unit9/coffee-bone divide et impera
  • 15. - GAE is not opinionated (which is good) - default webapp2 shipped with GAE is really super simple (a bit too simple…) - Flask is OK and does not have preferences for a specific ORM (which is great) - don’t use Django on GAE unless you really want to 
 (e.g. use legacy modules or deploy something really quick)
  • 16. class Jsonifiable(ndb.Model): def from_dict(cls, dict): pass def to_dict(self, async=False): pass def resolve_future_blobs(cls, async_blobs): pass class JsonRestHandler(webapp2.RequestHandler): JSON_MIMETYPE = "application/json" def write(self, data): self.response.out.write(data) def send_success(self, obj=None, cache_expiry=None): self.response.headers["Content-Type"] = self.JSON_MIMETYPE self.write(json.dumps(obj, cls=JsonifiableEncoder)) webapp2 bespoke REST micro-framework asynchronous conversion bespoke encoder basic permission check (skipped here) extend ndb.Model extend webapp2.RequestHandler
  • 17. kibble_authenticator = ModelAuthenticatior() admin = kibble.Kibble( 'admin', __name__, kibble_authenticator, label='Admin', static_url_path='/kibble/static', default_gcs_bucket=app_identity.get_default_gcs_bucket_name(), ) security_headers.apply(app) class CustomJsonEncoder(flask.json.JSONEncoder): def default(self, obj): try: if isinstance(obj, blobstore.BlobKey): return str(obj) if isinstance(obj, fields.Vertex): return [obj.x, obj.y, obj.z] if isinstance(obj, GCSFile): return obj.cloudstore_url if isinstance(obj, ndb.Key): return obj.flat() except TypeError: pass return super(CustomJsonEncoder, self).default(obj) app = flask.Flask(__name__, template_folder='../templates') app.json_encoder = CustomJsonEncoder admin.autodiscover(paths=['admin']) app.register_blueprint(admin, url_prefix='/admin') Flask Blueprints and GAE https://github.com/xlevus/flask-kibble
  • 18. 1. Google App Engine (GAE) and AngularJS 2. data structures 3. assets management 4. load testing 5. GAE benchmarking tool and task inspector 6. GAE asynchronous API
  • 19.
  • 20. this always seems a good way to start
  • 21. class ClubNight(BaseModel): name = ndb.StringProperty() content = ContentProperty(ndb.TextProperty) blob_key_logo = ContentProperty(ndb.BlobKeyProperty) genre = ndb.KeyProperty(kind=’Genre’) website = ContentProperty(ndb.StringProperty) address = ContentProperty(ndb.TextProperty) location = ContentProperty(ndb.GeoPtProperty) class Connection(ndb.Model): from_key = ndb.KeyProperty() to_key = ndb.KeyProperty() abstraction
  • 22. class ClubNight(BaseModel): name = ndb.StringProperty() content = ContentProperty(ndb.TextProperty) blob_key_logo = ContentProperty(ndb.BlobKeyProperty) genre = ndb.KeyProperty(kind=’Genre’) website = ContentProperty(ndb.StringProperty) address = ContentProperty(ndb.TextProperty) location = ContentProperty(ndb.GeoPtProperty) class Connection(ndb.Model): from_key = ndb.KeyProperty() to_key = ndb.KeyProperty() to_name = ndb.StringProperty() to_kind = ndb.StringProperty() to_slug = ndb.StringProperty() to_genre_colour = ndb.StringProperty() to_image = ndb.BlobKeyProperty() to_popularity = ndb.IntegerProperty() is_published = ndb.BooleanProperty() is_public = ndb.BooleanProperty(default=False) is_featured = ndb.BooleanProperty(default=False) reality
  • 23. class Vertex(namedtuple('Vertex', ['x', 'y', 'z'])): def __json__(self): return json.dumps(self) def __str__(self): return 'x={0.x:.2f}, y={0.y:.2f}, z={0.z:.2f}'.format(self) class VertexProperty(ndb.StringProperty): # Dummy XYZ field, used to quickly add validation through # admin.base.ModelConverter def _validate(self, value): if not isinstance(value, (tuple, Vertex)): raise TypeError("Expected Vertex got %r" % repr(value)) if len(value) != 3: raise TypeError("Expected 3-tuple/Vertex, got %r" % repr(value)) def _to_base_type(self, value): return "%s,%s,%s" % value def _from_base_type(self, value): if value: return Vertex(*[float(x) for x in value.split(",")]) return None finding the sweet spot
  • 24.
  • 25. 1. Google App Engine (GAE) and AngularJS 2. data structures 3. assets management 4. load testing 5. GAE benchmarking tool and task inspector 6. GAE asynchronous API
  • 26. The get_serving_url() method allows you to generate a stable, dedicated URL for serving web-suitable image thumbnails. You simply store a single copy of your original image in Blobstore, and then request a high-performance per-image URL. [https://cloud.google.com/appengine/docs/python/images/] ex. // Resize the image to 32 pixels (aspect-ratio preserved) http://your_app_id.appspot.com/randomStringImageId=s32 // Crop the image to 32 pixels http://your_app_id.appspot.com/randomStringImageId=s32-c Due diligence =s500 =s100
  • 27.
  • 28. - success == sleepless_nights (not for me! :P) - PR scheduled on all major funnels: - Google homepage - Youtube homepage - all major blogs (the verge, wired, etc.) - London silicon roundabout - 1.2M unique visits, 10M views during the FIRST 48H si vis pacem, para bellum
  • 29. from admin.publish_pipeline import Publish rec = urlmap.PublishRecord.new() p = Publish('admin.web.app', version=rec.key.id()) p.start() […] class Publish(Pipeline): """ Root Pipeline. Creates a :py:class:`common.models.urlmap.PublishRecord` for the pipeline, and spawns children. On completion, sets publish record to completed. """ def run(self, app, locales=None, version=None): rec = urlmap.PublishRecord.get_by_id(version) rec.pipeline_id = self.root_pipeline_id rec.put() urlmaps = yield URLMaps(version) with After(urlmaps): static = yield WriteStaticFiles.pipeline(app, version) sitemap = yield PublishSitemap(app, version) short_urls = yield CreateShortUrls.pipeline(app, version) with After(static, sitemap, short_urls): json = yield PublishJSON(app, version) with After(json): yield CleanShortUrls(app, version) yield Cleanup.pipeline() static publishing pipeline https://github.com/GoogleCloudPlatform/appengine-mapreduce/ create the pipeline and run process extend mapreduce pipeline spawn separate generators
  • 30. 1. Google App Engine (GAE) and AngularJS 2. data structures 3. assets management 4. load testing 5. GAE benchmarking tool and task inspector 6. GAE asynchronous API
  • 31. GAE docs are rubbish! :) i.e. read it, then forget it: https://cloud.google.com/appengine/articles/load_test 3rd party services are OK, but run your own if you can create a meaningful simulation of users’ behaviour hit it as hard as you can, but don’t forget your wallet!
  • 32. class ApiNav(TaskSet): @task(1) def api_global(self): self.client.get('/api/global?locale=%s' % langs[random.randint(0, len(langs)-1)], **kwargs) @task(1) def api_user(self): self.client.get('/api/user', **kwargs) @task(4) def api_gallery(self): self.client.get('/api/gallery?i=0&l=15', **kwargs) @task(8) def api_search(self): self.client.get('/api/gallery?i=0&l=15&q=%s' % terms[random.randint(0, len(terms)-1)], **kwargs) @task(6) def api_feeling_lucky(self): self.client.get('/api/page/feeling_lucky', **kwargs) @task(2) def api_big_gallery(self): self.client.get('/api/gallery?i=0&l=30', **kwargs) @task(2) def api_featured(self): self.client.get('/api/gallery?i=0&l=15&t=featured', **kwargs) class MyLocust(HttpLocust): host = 'https://sd-goog-devart.appspot.com' task_set = ApiNav min_wait = 5000 max_wait = 15000 locust init data gallery random search random project page categorized views
  • 33. - approximately 5000 concurrent user hitting the backend API with a "casual navigation" simulation from different location (London, New York, AWS data centre in Ireland) - 85 running instances (class F2) at peak - no errors reported other than random https sockets timeout - average response times - < 2s for gallery content navigation - < 1s for singe project page navitation - < 3s for static contend (loaded just once)
  • 34. 1. Google App Engine (GAE) and AngularJS 2. data structures 3. assets management 4. load testing 5. GAE benchmarking tool and task inspector 6. GAE asynchronous API
  • 35.
  • 36.
  • 37.
  • 38. 1. Google App Engine (GAE) and AngularJS 2. data structures 3. assets management 4. load testing 5. GAE benchmarking tool and task inspector 6. GAE asynchronous API
  • 39. @classmethod def fix_dict(cls, dict, async=False): async_blobs = [] def _fix_dict(k, v): # blob if isinstance(v, blobstore.BlobKey): try: # create futures and put them apart, we'll resolve these later output = {'key': str(v), 'url': '', 'rpc': images.get_serving_url_async(v, secure_url=True)} async_blobs.append(output) return output except BaseException as e: # logging.warn('error while fetching serving url for [%s] maybe using corrupted image?' % (v,)) return None for k, v in dict.iteritems(): dict[k] = _fix_dict(k, v) if async is True: return dict, async_blobs else: cls.resolve_future_blobs(async_blobs) return dict @classmethod def resolve_future_blobs(cls, async_blobs): # resolve futures for blob in async_blobs: try: blob['url'] = blob['rpc'].get_result() except BaseException: blob['url'] = '' del(blob['rpc']) get_serving_url_async 1. get async url 3. get real url 2. resolve future blobs
  • 40. Thanks! uh, just few notes: 1. we are hiring! check www.stinkdigital.com/careers and send us your CV - careers@stinkdigital.com 2. we organise a Meetup in London with UNIT9 and B-Reel, get in touch! tomalisi@stinkdigital.com 3. www.slideshare.net/grudelsud