Skip to content

Commit

Permalink
Add Memcache Best Practices Samples
Browse files Browse the repository at this point in the history
  • Loading branch information
Bill Prin committed Apr 27, 2016
1 parent 3345110 commit 435b0e7
Show file tree
Hide file tree
Showing 13 changed files with 349 additions and 0 deletions.
5 changes: 5 additions & 0 deletions appengine/memcache/best_practices/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Memcache Best Practices

Code snippets for [Memcache Cache Best Practices article](https://cloud.google.com/appengine/articles/best-practices-for-app-engine-memcache)


7 changes: 7 additions & 0 deletions appengine/memcache/best_practices/failure/app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: .*
script: failure.app
74 changes: 74 additions & 0 deletions appengine/memcache/best_practices/failure/failure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env python

# Copyright 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging

from google.appengine.api import memcache

import webapp2


def read_from_persistent_store():
"""Fake method for demonstration purposes. Usually would return
a value from a database like Cloud Datastore or MySQL."""
return "a persistent value"


class ReadPage(webapp2.RequestHandler):
def get(self):
key = "some-key"
# [START memcache-read]
v = memcache.get(key)
if v is None:
v = read_from_persistent_store()
memcache.add(key, v)
# [END memcache-read]

self.response.content_type = 'text/html'
self.response.write(str(v))


class DeletePage(webapp2.RequestHandler):
def get(self):
key = "some key"
seconds = 5
memcache.set(key, "some value")
# [START memcache-delete]
memcache.delete(key, seconds) # clears cache
# write to persistent datastore
# Do not attempt to put new value in cache, first reader will do that
# [END memcache-delete]
self.response.content_type = 'text/html'
self.response.write('done')


class MainPage(webapp2.RequestHandler):
def get(self):
value = 3
# [START memcache-failure]
if not memcache.set('counter', value):
logging.error("Memcache set failed")
# Other error handling here
# [END memcache-failure]
self.response.content_type = 'text/html'
self.response.write('done')


app = webapp2.WSGIApplication([
('/', MainPage),
('/delete', DeletePage),
('/read', ReadPage),
], debug=True)
35 changes: 35 additions & 0 deletions appengine/memcache/best_practices/failure/failure_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright 2016 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import failure

import pytest
import webtest


@pytest.fixture
def app(testbed):
return webtest.TestApp(failure.app)


def test_get(app):
app.get('/')


def test_read(app):
app.get('/read')


def test_delete(app):
app.get('/delete')
7 changes: 7 additions & 0 deletions appengine/memcache/best_practices/migration_step1/app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: .*
script: migration1.app
50 changes: 50 additions & 0 deletions appengine/memcache/best_practices/migration_step1/migration1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env python

# Copyright 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging

from google.appengine.api import memcache
from google.appengine.ext import ndb

import webapp2


# [START best-practice-1]
class Person(ndb.Model):
name = ndb.StringProperty(required=True)


def get_or_add_person(name):
person = memcache.get(name)
if person is None:
person = Person(name=name)
memcache.add(name, person)
else:
logging.info('Found in cache: ' + name)
return person
# [END best-practice-1]


class MainPage(webapp2.RequestHandler):
def get(self):
person = get_or_add_person('Stevie Wonder')
self.response.content_type = 'text/html'
self.response.write(person.name)


app = webapp2.WSGIApplication([
('/', MainPage),
], debug=True)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2016 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import migration1

import webtest


def test_get(testbed):
app = webtest.TestApp(migration1.app)
app.get('/')
7 changes: 7 additions & 0 deletions appengine/memcache/best_practices/migration_step2/app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: .*
script: migration2.app
51 changes: 51 additions & 0 deletions appengine/memcache/best_practices/migration_step2/migration2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env python

# Copyright 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging

from google.appengine.api import memcache
from google.appengine.ext import ndb

import webapp2


# [START best-practice-2]
class Person(ndb.Model):
name = ndb.StringProperty(required=True)
userid = ndb.StringProperty(required=True)


def get_or_add_person(name, userid):
person = memcache.get(name)
if person is None:
person = Person(name=name, userid=userid)
memcache.add(name, person)
else:
logging.info('Found in cache: ' + name + ', userid: ' + person.userid)
return person
# [END best-practice-2]


class MainPage(webapp2.RequestHandler):
def get(self):
person = get_or_add_person('Stevie Wonder', 1)
self.response.content_type = 'text/html'
self.response.write(person.name)


app = webapp2.WSGIApplication([
('/', MainPage),
], debug=True)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2016 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import migration2

import webtest


def test_get(testbed):
app = webtest.TestApp(migration2.app)
app.get('/')
7 changes: 7 additions & 0 deletions appengine/memcache/best_practices/sharing/app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: .*
script: sharing.app
39 changes: 39 additions & 0 deletions appengine/memcache/best_practices/sharing/sharing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env python

# Copyright 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


from google.appengine.api import memcache

import webapp2


class MainPage(webapp2.RequestHandler):
def get(self):
# [START sharing]
self.response.headers['Content-Type'] = 'text/plain'

who = memcache.get('who')
self.response.write('Previously incremented by %s\n' % who)
memcache.set('who', 'Python')

count = memcache.incr('count', 1, initial_value=0)
self.response.write('Count incremented by Python = %s\n' % count)
# [END sharing]


app = webapp2.WSGIApplication([
('/', MainPage),
], debug=True)
23 changes: 23 additions & 0 deletions appengine/memcache/best_practices/sharing/sharing_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright 2016 Google Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import sharing

import webtest


def test_get(testbed):
app = webtest.TestApp(sharing.app)
response = app.get('/')
assert 'Previously incremented by ' in response.body

0 comments on commit 435b0e7

Please sign in to comment.