Skip to content

Commit

Permalink
Merge pull request #26 from GoogleCloudPlatform/fix-memcached
Browse files Browse the repository at this point in the history
Cleaned up memcached example and added tests.
  • Loading branch information
jmdobry committed Nov 13, 2015
2 parents 6f1324f + 4b16030 commit 0475cde
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 87 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ cache:

services:
- redis-server
- memcached
- docker

env:
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and applications on [Google App Engine](http://cloud.google.com/nodejs).
### Frameworks

- Express.js - [Source code][express_1] | [App Engine Tutorial][express_2] | [Live demo][express_3] | [Documentation][express_4]
- Express.js + Memcached Sessions - [Source code][express_5] | [Documentation][express_6]
- Geddy.js - [Source code][geddy_1] | [App Engine Tutorial][geddy_2] | [Live demo][geddy_3] | [Documentation][geddy_4]
- Hapi.js - [Source code][hapi_1] | [App Engine Tutorial][hapi_2] | [Live demo][hapi_3] | [Documentation][hapi_4]
- Loopback.js - [Source code][loopback_1] | [App Engine Tutorial][loopback_2] | [Live demo][loopback_3] | [Documentation][loopback_4]
Expand Down Expand Up @@ -68,6 +69,8 @@ See [LICENSE](https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/ma
[express_2]: https://cloud.google.com/nodejs/resources/frameworks/express
[express_3]: http://express-dot-nodejs-docs-samples.appspot.com
[express_4]: http://expressjs.com/
[express_5]: https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/master/appengine/express-memcached-session
[express_6]: https://github.com/balor/connect-memcached

[geddy_1]: https://github.com/GoogleCloudPlatform/nodejs-docs-samples/blob/master/appengine/geddy
[geddy_2]: https://cloud.google.com/nodejs/resources/frameworks/geddy
Expand Down
132 changes: 80 additions & 52 deletions appengine/express-memcached-session/README.md
Original file line number Diff line number Diff line change
@@ -1,65 +1,93 @@
# Express + Memcached Sessions -> Google App Engine
## Express.js + Memcached Sessions on Google App Engine

This is a simple guide to using memcached for session state while running [expressjs](http://expressjs.com/) on Google App Engine. Each Google App Engine application comes with a memcached service instance, which can be reached with a standard memcached driver at `memcache:11211`.
This is a simple guide to using memcached for session state while running
[Express.js](http://expressjs.com/) on Google App Engine. Each Google App Engine
application comes with a memcached service instance, which can be reached with a
standard memcached driver at `memcache:11211`. This sample uses the
[connect-memcached](https://github.com/balor/connect-memcached) module to store
session data in memcached.

1. [Create a new Express app](http://expressjs.com/starter/generator.html)
## Clone the Express.js + Memcached Sessions app

2. Create an `app.yaml` in the root of your application with the following contents:
If you haven't already, copy the repository to your local machine by entering
the following command in your terminal window:

```yaml
runtime: nodejs
vm: true
env_variables:
PORT: 8080
MEMCACHE_URL: memcache:11211
```
```
$ git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git
$ cd nodejs-docs-samples/appengine/express-memcached-session
```

Alternatively, you can [download the sample][download] as a zip and extract it.

## Run the app on your local computer

1. Install dependencies. Enter the following command:

Notice the MEMCACHE_URL environment variable - this is where you can reach your standard memcached cluster across instances.
3. Use the [connect-memcached](https://github.com/balor/connect-memcached) module. Run `npm install --save connect-memcached`, and add the following to your server.js or app.js:

```js
var MemcachedStore = require('connect-memcached')(session);
...
app.use(session({
secret: 'appengineFTW',
key: 'test',
proxy: 'true',
store: new MemcachedStore({
hosts: [process.env.MEMCACHE_URL || '127.0.0.1:11211']
})
}));
```
4. In your express route handlers, you can now safely use `req.session.*` across multiple nodejs instances:

```js
app.get('/', function(req, res){
publicIp.v4(function (err, ip) {
res.write("<div>" + ip + "</div>");
if(req.session.views) {
++req.session.views;
} else {
req.session.views = 1;
}
res.end('Viewed <strong>' + req.session.views + '</strong> times.');
});
});
$ npm install
```

5. To test the sample locally, you can install memcached.
- OSX + [Brew](http://brew.sh/): `brew install memcached`
- Windows + [Chocolatey](https://chocolatey.org/packages/memcached): `choco install memcached`
2. Run the start script.

Run memcached on localhost:11211 by running `memcached`

````
$ npm start
```
6. Deploy your app. For convenience, you can use an npm script to run the command. Modify your `package.json` to include:
3. In your web browser, enter the following address:
```js
"scripts": {
"start": "node server.js",
"deploy": "gcloud preview app deploy app.yaml --set-default --project [project id]"
}
```
$ http://localhost:8080
```
You can see the sample app displayed in the page. This page was delivered by the
Express.js web server running on your computer.
In your terminal window, press Ctrl+C to exit the web server.
## Deploy the app to Google Cloud Platform
In your terminal window, enter the following command to deploy the sample:
```
$ gcloud preview app deploy app.yaml --promote
```
### See the app run in the cloud
In your web browser, enter the following address:
```
https://<your-project-id>.appspot.com
```
For convenience, you can use an npm script to run the gcloud command. Add these lines to your package.json file:
```
"scripts": {
"start": "node server.js",
"deploy": "gcloud preview app deploy app.yaml --promote --project <your-project-id>"
}
```
At the terminal you can now run the following command to deploy your application:
```
$ npm run deploy
```
## Configuration
Every Managed VMs application requires an app.yaml file to describe its deployment configuration.
```yaml
runtime: nodejs
vm: true
env_variables:
PORT: 8080
MEMCACHE_URL: memcache:11211
```
Notice the `MEMCACHE_URL` environment variable–this is where you can reach your
standard memcached cluster across instances.
At the terminal you can now run `npm run deploy` to deploy your application.
[download]: https://github.com/GoogleCloudPlatform/nodejs-docs-samples/archive/master.zip
1 change: 0 additions & 1 deletion appengine/express-memcached-session/app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
# limitations under the License.

runtime: nodejs
api_version: 1
vm: true
env_variables:
PORT: 8080
Expand Down
16 changes: 11 additions & 5 deletions appengine/express-memcached-session/package.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
{
"name": "express-memcached-session-demo",
"version": "1.0.0",
"name": "appengine-express-memcached-session",
"description": "An example of using memcached for sessions in Express.js on Google App Engine.",
"version": "0.0.1",
"private": true,
"license": "Apache Version 2.0",
"engines": {
"node": "~0.12.7"
},
"scripts": {
"deploy": "gcloud preview app deploy app.yaml --set-default --project express-memcached-demo"
"start": "node server.js",
"deploy": "gcloud preview app deploy app.yaml"
},
"dependencies": {
"connect-memcached": "^0.1.0",
"cookie-parser": "~1.3.5",
"express": "~4.12.4",
"cookie-parser": "^1.3.5",
"express": "^4.12.4",
"express-session": "^1.11.3",
"public-ip": "^1.1.0"
}
Expand Down
45 changes: 24 additions & 21 deletions appengine/express-memcached-session/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,40 @@
var express = require('express');
var session = require('express-session');
var cookieParser = require('cookie-parser');
var http = require('http');
var MemcachedStore = require('connect-memcached')(session);
var publicIp = require('public-ip');

var app = express();

app.use(cookieParser());
app.use(session({
secret: 'appengineFTW',
key: 'test',
proxy: 'true',
store: new MemcachedStore({
hosts: [process.env.MEMCACHE_URL || '127.0.0.1:11211']
})
secret: 'your-secret-here',
key: 'view:count',
proxy: 'true',
store: new MemcachedStore({
hosts: [process.env.MEMCACHE_URL || '127.0.0.1:11211']
})
}));

app.get('/', function(req, res){
publicIp.v4(function (err, ip) {

// This shows the IP for each
res.write('<div>' + ip + '</div>');
if(req.session.views) {
++req.session.views;
} else {
req.session.views = 1;
}
res.end('Viewed <strong>' + req.session.views + '</strong> times.');
});
publicIp.v4(function (err, ip) {

// This shows the IP for each
res.write('<div>' + ip + '</div>');

if(req.session.views) {
++req.session.views;
} else {
req.session.views = 1;
}
res.end('Viewed <strong>' + req.session.views + '</strong> times.');
});
});

http.createServer(app).listen(process.env.PORT || 8080, function() {
if (module === require.main) {
app.listen(process.env.PORT || 8080, function() {
console.log('Listening on %d', this.address().port);
});
});
}

module.exports = app;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"cover": "istanbul cover --hook-run-in-context node_modules/mocha/bin/_mocha -- --timeout 10000 --recursive",
"coveralls": "cat ./coverage/lcov.info | node_modules/.bin/coveralls",
"pretest_express": "cd appengine/express && npm install && cd ../..",
"pretest_memcached": "cd appengine/express-memcached-session && npm install && cd ../..",
"pretest_geddy": "cd appengine/geddy && npm install geddy; GEDDY_SECRET=config/secrets.json; [[ -f $GEDDY_SECRET ]] || echo '{}' > $GEDDY_SECRET && node node_modules/.bin/geddy gen secret; cd ../..;",
"pretest": "npm run pretest_express && npm run pretest_geddy",
"test": "npm run jshint && npm run cover"
Expand Down
23 changes: 15 additions & 8 deletions test/appengine/all.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ var sampleTests = [
msg: 'Hello World! Express.js on Google App Engine.',
TRAVIS_NODE_VERSION: '0.10'
},
{
dir: 'express-memcached-session',
cmd: 'node',
args: ['server.js'],
msg: 'Viewed',
TRAVIS_NODE_VERSION: '0.10'
},
{
dir: 'geddy',
deploy: true,
Expand Down Expand Up @@ -82,12 +89,12 @@ var sampleTests = [
args: ['app.js'],
msg: 'Express.js + Mailgun on Google App Engine.'
},
// {
// dir: 'redis',
// cmd: 'node',
// args: ['server.js'],
// msg: '127.0.0.1'
// },
{
dir: 'redis',
cmd: 'node',
args: ['server.js'],
msg: '127.0.0.1'
},
{
dir: 'restify',
deploy: true,
Expand All @@ -112,7 +119,7 @@ if (process.env.TRAVIS_NODE_VERSION === '0.10') {
});
}

//if (process.env.TRAVIS_NODE_VERSION === 'stable') {
if (process.env.TRAVIS_NODE_VERSION === 'stable') {
// For some reason the "npm install" step for the Sails sample doesn't work on
// Travis when using Node.js stable. It works locally, however.
sampleTests.push({
Expand All @@ -123,7 +130,7 @@ if (process.env.TRAVIS_NODE_VERSION === '0.10') {
msg: 'Hello World! Koa.js on Google App Engine.',
TRAVIS_NODE_VERSION: 'stable'
});
//}
}

// Send a request to the given url and test that the response body has the
// expected value
Expand Down
26 changes: 26 additions & 0 deletions test/appengine/express-memcached-session.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2015, 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.

'use strict';

var request = require('supertest');
var app = require('../../appengine/express-memcached-session/server.js');

describe('express-memcached-session', function () {
it('should return 200', function (done) {
request(app)
.get('/')
.expect(200)
.end(done);
});
});

0 comments on commit 0475cde

Please sign in to comment.