Cloud World

  • Subscribe to our RSS feed.
  • Twitter
  • StumbleUpon
  • Reddit
  • Facebook
  • Digg

Wednesday, 23 February 2011

Pushing Updates with the Channel API

Posted on 15:48 by Unknown

If you've been watching Best Buy closely, you already know that Best Buy is constantly trying to come up with new and creative ways to use App Engine to engage with their customers. In this guest blog post, Luke Francl, BBYOpen Developer, was kind enough to share with us Best Buy's latest App Engine project.







As part of Best Buy's Connected Store initiative, we have placed QR codes on our product information Fact Tags, in addition to the standard pricing and product descriptions already printed there. When a customer uses the Best Buy app, or any other QR code scanner, they are shown the product details for the product they have scanned, powered by the BBYOpen API or the m.bestbuy.com platform.



To track what stores and products are most popular, QR codes are also encoded with the store number. My project at Best Buy has been to analyze these scans and make new landing pages for QR codes easier to create.



Since we have the geo-location of the stores and product details from our API, it is a natural fit to display these scans on a map. We implemented an initial version of this idea, which used polling to visualize recent scans. To take our this a step further, we thought it would be exciting to use the recently launched App Engine Channel API to update our map in real-time.








Our biggest challenge was pushing the updates to multiple browsers, since we'd most certainly have more than one user at a time looking at our map. The Channel API does not currently support broadcasting a single update to many connected clients. In order to broadcast updates to multiple users, our solution was to keep a list of client IDs and send an update message to each of them.



To implement this, we decided to store the list of active channels in memcache. This solution is not ideal as there are race conditions when we modify the list of client IDs. However, it works well for our demo.



Here’s how we got it working. The code has been slightly simplified for clarity, including removing the rate limiting that we do. To play with a working demo, check out the channel-map-demo project from GitHub.



As customers in our stores scan QR codes, those scans are recorded by enqueuing a deferred. We defer all writes so we can return a response to the client as quickly as possible.



In the deferred, we call a function to push the message to all the active channels (see full source).




def push_to_channels(scan):
content = '<div class="infowindowcontent">(...) </div>' % {
'product_name': scan.product.name,
'timestamp' : scan.timestamp.strftime('%I:%M %p'),
'store_name': scan.store.name,
'state': scan.store.state,
'image': scan.product.image }

message = {'lat': scan.store.lat,
'lon': scan.store.lon,
'content': content}

channels = simplejson.loads(memcache.get('channels') or '{}')

for channel_id in channels.iterkeys():
encoded_message = simplejson.dumps(message)

channel.send_message(channel_id, encoded_message)


The message is a JSON data structure containing the latitude and longitude of the store where the scan occurred, plus a snippet of HTML to display in an InfoWindow on the map. The product information (such as name and thumbnail image) comes from our BBYOpen Products API.



Then, when a user opens up the site and requests the map page, we create a channel, add it to the serialized channels Python dictionary, stored in memcache, and pass the token back to the client (see full source).




channel_id = uuid.uuid4().hex
token = channel.create_channel(channel_id)

channels = simplejson.loads(memcache.get('channels') or '{}')

channels[channel_id] = str(datetime.now())

memcache.set('channels', simplejson.dumps(channels))


On the map page, JavaScript creates a Google Maps map and uses the token to open a channel. When the onMessage callback is called by the Channel API, a new InfoWindow is displayed on the map using the HTML content and latitude and longitude in the message (see full source).




function onMessage(message) {
var scan = JSON.parse(message.data);

var infoWindow = new google.maps.InfoWindow(
{content: scan.content,
disableAutoPan: true,
position: new google.maps.LatLng(scan.lat, scan.lon)});

infoWindow.open(map);
setTimeout(function() { infoWindow.close(); }, 10000);
};


Finally, since channels can only be open for two hours, we have a cron job that runs once an hour to remove old channels. Before deleting the client ID, a message is sent on the channel which triggers code in the JavaScript onMessage function to reload the page, thus giving it a new channel and client ID (see full source).



You can see the end result on our map, watch a video about the BBYScan project or checkout the sample channel-map-demo project and create your own Channel API based application.



Posted by Fred Sauer, App Engine Team
Email ThisBlogThis!Share to XShare to Facebook
Posted in | No comments
Newer Post Older Post Home

0 comments:

Post a Comment

Subscribe to: Post Comments (Atom)

Popular Posts

  • A Day in the Cloud, new articles on scaling, and fresh open source projects for App Engine
    The latest release of Python SDK 1.2.3, which introduced the Task Queue API and integrated support for Django 1.0, may have received a lot ...
  • Cube Slam meets Google Cloud Platform
    The Google Creative Lab team has built another fun Chrome Experiment called Cube Slam . Cube Slam connects players into a three dimensional,...
  • GDC’13: Learn how to build games on Google Cloud Platform
    At the Game Developers Conference last month, we held a day of sessions showing developers how to take advantage of Google Cloud Platform ...
  • New in Google Cloud Storage: auto-delete, regional buckets and faster uploads
    We’ve launched new features in Google Cloud Storage that make it easier to manage objects, and faster to access and upload data. With a tiny...
  • DataStax Enterprise feels right at home in Google Compute Engine
    Today’s guest post comes from Martin Van Ryswyk, Vice President of Engineering at DataStax. The cloud promises many things for database user...
  • Outfit 7’s Talking Friends built on Google App Engine, recently hit one billion downloads
    Today’s guest blogger is Igor Lautar, senior director of technology at Outfit7 (Ekipa2 subsidiary), one of the fastest-growing media enterta...
  • Jump-start your data pipelining into Google BigQuery
    Once you get your data into Google BigQuery , you don’t have to worry about running out of machine capacity, because you use Google’s machin...
  • Development in the Cloud with Codenvy and Google Cloud Platform
    Today’s post is from Tyler Jewell, CEO at Codenvy. In this post, Tyler looks at how you can leverage cloud based development tools to build ...
  • Get started at no cost with a faster, larger Google Cloud SQL database
    You want your application to be fast. Databases play a big role in your overall application speed and end-users’ experience. Reads and write...
  • The BugSense hybrid app: experiences using Clojure on Google App Engine
    Today’s post comes to us from Jon Vlachogiannis and Panos Papadopoulos , founders of BugSense , a mobile error analytics service. We hope y...

Categories

  • 1.1.2
  • agile
  • android
  • Announcements
  • api
  • app engine
  • appengine
  • batch
  • bicycle
  • bigquery
  • canoe
  • casestudy
  • cloud
  • Cloud Datastore
  • cloud endpoints
  • cloud sql
  • cloud storage
  • cloud-storage
  • community
  • Compute Engine
  • conferences
  • customer
  • datastore
  • delete
  • developer days
  • developer-insights
  • devfests
  • django
  • email
  • entity group
  • events
  • getting started
  • google
  • googlenew
  • gps
  • green
  • Guest Blog
  • hadoop
  • html5
  • index
  • io2010
  • IO2013
  • java
  • kaazing
  • location
  • mapreduce
  • norex
  • open source
  • partner
  • payment
  • paypal
  • pipeline
  • put
  • python
  • rental
  • research project
  • solutions
  • support
  • sustainability
  • taskqueue
  • technical
  • toolkit
  • twilio
  • video
  • websockets
  • workflows

Blog Archive

  • ►  2013 (143)
    • ►  December (33)
    • ►  November (15)
    • ►  October (17)
    • ►  September (13)
    • ►  August (4)
    • ►  July (15)
    • ►  June (12)
    • ►  May (15)
    • ►  April (4)
    • ►  March (4)
    • ►  February (9)
    • ►  January (2)
  • ►  2012 (43)
    • ►  December (2)
    • ►  November (2)
    • ►  October (8)
    • ►  September (2)
    • ►  August (3)
    • ►  July (4)
    • ►  June (2)
    • ►  May (3)
    • ►  April (4)
    • ►  March (5)
    • ►  February (3)
    • ►  January (5)
  • ▼  2011 (46)
    • ►  December (3)
    • ►  November (4)
    • ►  October (4)
    • ►  September (5)
    • ►  August (3)
    • ►  July (4)
    • ►  June (3)
    • ►  May (8)
    • ►  April (2)
    • ►  March (5)
    • ▼  February (3)
      • Pushing Updates with the Channel API
      • App Engine 1.4.2 SDK - API Updates and Additions E...
      • Beauty On the Outside, High Replication on the Inside
    • ►  January (2)
  • ►  2010 (38)
    • ►  December (2)
    • ►  October (2)
    • ►  September (1)
    • ►  August (5)
    • ►  July (5)
    • ►  June (6)
    • ►  May (3)
    • ►  April (5)
    • ►  March (5)
    • ►  February (2)
    • ►  January (2)
  • ►  2009 (47)
    • ►  December (4)
    • ►  November (3)
    • ►  October (6)
    • ►  September (5)
    • ►  August (3)
    • ►  July (3)
    • ►  June (4)
    • ►  May (3)
    • ►  April (5)
    • ►  March (3)
    • ►  February (7)
    • ►  January (1)
  • ►  2008 (46)
    • ►  December (4)
    • ►  November (3)
    • ►  October (10)
    • ►  September (5)
    • ►  August (6)
    • ►  July (4)
    • ►  June (2)
    • ►  May (5)
    • ►  April (7)
Powered by Blogger.

About Me

Unknown
View my complete profile