Google Appengine 1.4.0 was just released and has lots of interesting new features. Channel API, "Always On" (reserved instances), Improvements to background processing, Warm up requests, and Metadata queries just to name the big ones.

Channel API

The Channel API is a way for you to "push" data to the client browser. The Channel is a bit like a socket connection but it's implemented using Google's XMPP infrastructure built for Google Talk. So it will scale properly as needed.

The Channel API feature includes two parts, a server-side API for creating channels and sending messages, and a Javascript API for recieving and processing those messages.

Let's take a look and what a simple application might look like to demonstrate the API.

Server-Side

First we need to create a channel. We give it a unique channel key and it will give us an ID that we can give to the client, who will in turn use the ID to connect to the channel to recieve messsages.

Here we are passing the current user object to channel.create_channel() but any string will do. So you could have many clients listening to the same channel designated by an arbitrary key.

from google.appengine.ext import webapp
from google.appengine.api import channel
from django.template.loader import render_to_string

class MyHandler(BaseHandler):
    def get(self):
        user = users.get_current_user()

        # Create the channel
        # We could pass a string to create_channel() if we wanted to.
        id = channel.create_channel(user)

        return self.response.out.write(
            render_to_string(
                "index.html",
                {"channel_id": id},
            )
        )

On the client site we use javascript to connect to the channel.

var channel = new goog.appengine.Channel("{{ channel_id }}");
var socket = channel.open();
socket.onopen = function() {
    window.setTimeout(function() {alert('Connected!')}, 100);
}

// Register a message handler
socket.onmessage = function(evt) {
     // Here we are getting text from the server
     // But JSON data is recommended.
     // var o = JSON.parse(evt.data);
     alert(evt.data);
     // do something
}

Last, we can send a message to the client using the user as the channel key.

from google.appengine.api import channel
from google.appengine.api import users

class AjaxHandler(BaseHandler):
    def get(self):
        user = users.get_current_user()

        # Send a message to the client.
        # Noone actually needs to be connected
        # If sending to a channel where noone
        # is connected then this does nothing.
        channel.send_message(user, "Hello World!!")

Note

The channel API is not a two-way channel. It is for pushing data to the client. If you want to send data to the server you can do so using normal AJAX POST requests.

Always On

The "Always On" feature lets you pay to keep at least 3 instances running at all times. Until now your application could go completely cold with no instances running. When a user made a request for the first time, Appengine would have to spin up an instance in order to serve the request, which could take a lot of time.

Note

Something to note is that this is only really effective for applications that have times where their application falls below 3 instances. If your application always has enough traffic to keep appengine above 3 instances then this feature won't do anything for you.

Warmup Requests

Until now, when a request came that would cause Appengine to scale out and create a new instance, it would need to send the request to your instance cold. i.e. Your instance wouldn't have a chance to load modules before the request came, so that particular request would be served slowly.

Warmup requests are requests that are sent to your instance as the first request before serving user facing requests. This allows you to load heavy modules before serving user facing requests, allowing for a much better experience for users.

In order to enable Warmup Requests, you need to add warmup to your inbound_services section of your app.yaml much like you would for mail or XMPP.

inbound_services:
- warmup

The warmup request will be sent to /_ah/warmup so you can add a handler to your app.yaml to specifically handle the request or just use a catch all handler.

Here we'll use our own handler.

- url: /_ah/warmup.*
  script: warmup.py

Our warmup.py might look like this.

# Load some big modules that we need for our application here
import mybigmodule
import myothermodule

def main():
    print "Content-type: text/plain"
    print "OK"

Task Queue Official Release

In 1.4.0, The task queue graduates from labs and becomes a first class feature of Appengine. This means that the taskqueue API module will move from google.appengine.api.labs.taskqueue to google.appengine.api.taskqueue. You can still import the task queue API from the old module but it will give you a deprecation warning on the development server and could be removed in future versions.

Task Queue tasks were not previously counted against your storage quota but they will be now so heavy users might need to start watching their data quota more closely.

Improved Background Processing

Cron and Task Queue tasks are going from having a request limit of 30 seconds to having a request limit of 10 minutes. This is a huge jump!! but it doesn't mean that you can be lazy now. Appengine will recognize long running cron jobs and tasks and process them separately (in a separate queue/different infrastructure) from fast running cron jobs/tasks. So you won't be able to get high throughput for long running tasks. This means you will only be able to do a few long running tasks or cron jobs at a time without backing things up.

Metadata Queries

You can now do queries against Appengine Datastore metadata. The SDK now provides new Namespace, Kind, and Property Model classes that live in google.appengine.ext.db.metadata. You can query these like regular models but you won't be able to create new ones by saving them to the datastore like you would be with regular modules.

Namespaces are pretty trivial. Kinds are parent objects of their properties so you can get the properties for a particular kind by doing an ancestor query.

from google.appengine.ext.db.metadata import Namespace, Kind, Property

for namespace in Namespace.all():
    print namespace.namespace_name

for kind in Kind.all():
    print kind.kind_name
    for property in Property.all().ancestor(kind):
        print "    %s" % property.property_name

Download

It looks like the download hasn't made it to the appengine download page yet but you can download it from the links at the google project page.