Skip to content

Commit

Permalink
Merge pull request #294 from GoogleCloudPlatform/best_memcache
Browse files Browse the repository at this point in the history
Add Memcache Best Practices Samples
  • Loading branch information
waprin committed Apr 28, 2016
2 parents fe59a33 + 98c3049 commit 7b9ee96
Show file tree
Hide file tree
Showing 16 changed files with 415 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/batch/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: batch.app
35 changes: 35 additions & 0 deletions appengine/memcache/best_practices/batch/batch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/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


class MainPage(webapp2.RequestHandler):
def get(self):
# [START batch]
values = {'comment': 'I did not ... ', 'comment_by': 'Bill Holiday'}
if not memcache.set_multi(values):
logging.error('Unable to set Memcache values')
tvalues = memcache.get_multi(('comment', 'comment_by'))
self.response.write(tvalues)
# [END batch]

app = webapp2.WSGIApplication([
('/', MainPage),
], debug=True)
28 changes: 28 additions & 0 deletions appengine/memcache/best_practices/batch/batch_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# 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 batch

import pytest
import webtest


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


def test_get(app):
response = app.get('/')
assert 'Bill Holiday' in response.body
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
73 changes: 73 additions & 0 deletions appengine/memcache/best_practices/failure/failure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/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
49 changes: 49 additions & 0 deletions appengine/memcache/best_practices/migration_step1/migration1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/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
50 changes: 50 additions & 0 deletions appengine/memcache/best_practices/migration_step2/migration2.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-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
Loading

0 comments on commit 7b9ee96

Please sign in to comment.