Skip to content

Commit 7b9ee96

Browse files
committed
Merge pull request #294 from GoogleCloudPlatform/best_memcache
Add Memcache Best Practices Samples
2 parents fe59a33 + 98c3049 commit 7b9ee96

File tree

16 files changed

+415
-0
lines changed

16 files changed

+415
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Memcache Best Practices
2+
3+
Code snippets for [Memcache Cache Best Practices article](https://cloud.google.com/appengine/articles/best-practices-for-app-engine-memcache)
4+
5+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
runtime: python27
2+
threadsafe: yes
3+
api_version: 1
4+
5+
handlers:
6+
- url: .*
7+
script: batch.app
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2016 Google Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import logging
18+
19+
from google.appengine.api import memcache
20+
import webapp2
21+
22+
23+
class MainPage(webapp2.RequestHandler):
24+
def get(self):
25+
# [START batch]
26+
values = {'comment': 'I did not ... ', 'comment_by': 'Bill Holiday'}
27+
if not memcache.set_multi(values):
28+
logging.error('Unable to set Memcache values')
29+
tvalues = memcache.get_multi(('comment', 'comment_by'))
30+
self.response.write(tvalues)
31+
# [END batch]
32+
33+
app = webapp2.WSGIApplication([
34+
('/', MainPage),
35+
], debug=True)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import batch
16+
17+
import pytest
18+
import webtest
19+
20+
21+
@pytest.fixture
22+
def app(testbed):
23+
return webtest.TestApp(batch.app)
24+
25+
26+
def test_get(app):
27+
response = app.get('/')
28+
assert 'Bill Holiday' in response.body
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
runtime: python27
2+
threadsafe: yes
3+
api_version: 1
4+
5+
handlers:
6+
- url: .*
7+
script: failure.app
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2016 Google Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import logging
18+
19+
from google.appengine.api import memcache
20+
import webapp2
21+
22+
23+
def read_from_persistent_store():
24+
"""Fake method for demonstration purposes. Usually would return
25+
a value from a database like Cloud Datastore or MySQL."""
26+
return "a persistent value"
27+
28+
29+
class ReadPage(webapp2.RequestHandler):
30+
def get(self):
31+
key = "some-key"
32+
# [START memcache-read]
33+
v = memcache.get(key)
34+
if v is None:
35+
v = read_from_persistent_store()
36+
memcache.add(key, v)
37+
# [END memcache-read]
38+
39+
self.response.content_type = 'text/html'
40+
self.response.write(str(v))
41+
42+
43+
class DeletePage(webapp2.RequestHandler):
44+
def get(self):
45+
key = "some key"
46+
seconds = 5
47+
memcache.set(key, "some value")
48+
# [START memcache-delete]
49+
memcache.delete(key, seconds) # clears cache
50+
# write to persistent datastore
51+
# Do not attempt to put new value in cache, first reader will do that
52+
# [END memcache-delete]
53+
self.response.content_type = 'text/html'
54+
self.response.write('done')
55+
56+
57+
class MainPage(webapp2.RequestHandler):
58+
def get(self):
59+
value = 3
60+
# [START memcache-failure]
61+
if not memcache.set('counter', value):
62+
logging.error("Memcache set failed")
63+
# Other error handling here
64+
# [END memcache-failure]
65+
self.response.content_type = 'text/html'
66+
self.response.write('done')
67+
68+
69+
app = webapp2.WSGIApplication([
70+
('/', MainPage),
71+
('/delete', DeletePage),
72+
('/read', ReadPage),
73+
], debug=True)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import failure
16+
17+
import pytest
18+
import webtest
19+
20+
21+
@pytest.fixture
22+
def app(testbed):
23+
return webtest.TestApp(failure.app)
24+
25+
26+
def test_get(app):
27+
app.get('/')
28+
29+
30+
def test_read(app):
31+
app.get('/read')
32+
33+
34+
def test_delete(app):
35+
app.get('/delete')
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
runtime: python27
2+
threadsafe: yes
3+
api_version: 1
4+
5+
handlers:
6+
- url: .*
7+
script: migration1.app
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2016 Google Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import logging
18+
19+
from google.appengine.api import memcache
20+
from google.appengine.ext import ndb
21+
import webapp2
22+
23+
24+
# [START best-practice-1]
25+
class Person(ndb.Model):
26+
name = ndb.StringProperty(required=True)
27+
28+
29+
def get_or_add_person(name):
30+
person = memcache.get(name)
31+
if person is None:
32+
person = Person(name=name)
33+
memcache.add(name, person)
34+
else:
35+
logging.info('Found in cache: ' + name)
36+
return person
37+
# [END best-practice-1]
38+
39+
40+
class MainPage(webapp2.RequestHandler):
41+
def get(self):
42+
person = get_or_add_person('Stevie Wonder')
43+
self.response.content_type = 'text/html'
44+
self.response.write(person.name)
45+
46+
47+
app = webapp2.WSGIApplication([
48+
('/', MainPage),
49+
], debug=True)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import migration1
16+
17+
import webtest
18+
19+
20+
def test_get(testbed):
21+
app = webtest.TestApp(migration1.app)
22+
app.get('/')
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
runtime: python27
2+
threadsafe: yes
3+
api_version: 1
4+
5+
handlers:
6+
- url: .*
7+
script: migration2.app
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2016 Google Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import logging
18+
19+
from google.appengine.api import memcache
20+
from google.appengine.ext import ndb
21+
import webapp2
22+
23+
24+
# [START best-practice-2]
25+
class Person(ndb.Model):
26+
name = ndb.StringProperty(required=True)
27+
userid = ndb.StringProperty(required=True)
28+
29+
30+
def get_or_add_person(name, userid):
31+
person = memcache.get(name)
32+
if person is None:
33+
person = Person(name=name, userid=userid)
34+
memcache.add(name, person)
35+
else:
36+
logging.info('Found in cache: ' + name + ', userid: ' + person.userid)
37+
return person
38+
# [END best-practice-2]
39+
40+
41+
class MainPage(webapp2.RequestHandler):
42+
def get(self):
43+
person = get_or_add_person('Stevie Wonder', "1")
44+
self.response.content_type = 'text/html'
45+
self.response.write(person.name)
46+
47+
48+
app = webapp2.WSGIApplication([
49+
('/', MainPage),
50+
], debug=True)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Copyright 2016 Google Inc. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import migration2
16+
17+
import webtest
18+
19+
20+
def test_get(testbed):
21+
app = webtest.TestApp(migration2.app)
22+
app.get('/')
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
runtime: python27
2+
threadsafe: yes
3+
api_version: 1
4+
5+
handlers:
6+
- url: .*
7+
script: sharing.app

0 commit comments

Comments
 (0)