15

It seems the only way to make the GAE Channel API financially viable is to implement some kind of pooling mechanism (one of the senior app engine product managers even told me this when I emailed them about the exorbitant price) to reuse channels that have not yet expired.

I've been brainstorming ways (places) to implement a channel pool, but each method I think of has some pretty serious drawbacks.

Static memory of a Servlet -- Good, but will drop quite a bit of open channels when a new VM instance opens and/or a client gets passed from one VM to another.

Memcache -- At least the memory is globally accessible from all VMs, but now the possibility of dropping a very viable channel is possibly greater due to inactivity and memory pressure.

Backend Instance -- Probably the best option in terms of reliability, but now the expense of running the backend will eat up all the savings of implementing the pool in the first place!

Is there a better place/way of implementing a channel pool across VMs that I'm missing, or am I unnecessarily hung up on the drawbacks of my options here? I really hope there is, or it looks like my app will have to revert to polling (which is looking marginally cheaper in my preliminary metrics).

Eternal Rubyist
  • 3,445
  • 4
  • 34
  • 51
  • Can you store them in the datastore with a timestamp, then run a cron to delete the expired ones? Although the read/write ops will cost you as well... – Jon Newmuis Nov 16 '11 at 06:00
  • @Jonathan Newmuis Yeah that kinda goes along with the Memcache solution, but like you mentioned, it certainly is not without a cost. Perhaps with the two of them working in conjunction that would be the most viable option... Anybody have any metrics or experience attempting this? – Eternal Rubyist Nov 16 '11 at 17:40
  • can you add some information about what your software does? – AlfredoVR Dec 19 '11 at 20:56
  • @alfa64 My application is a massively multiplayer social game that pushes critical game state updates dynamically to specific clients in real-time. The catch is that a usual usecase involves a player signing on for couple minutes, probably 15 at the max, before signing off. This essentially wastes at least 85% of (presently) the most expensive resource on app engine, making it utterly non-viable despite its fantastic functionality. – Eternal Rubyist Dec 20 '11 at 22:12
  • 1
    It seems that Channel creation is free now, so if the concern is only financial viability, this should no longer be an issue. – Pixel Elephant Oct 31 '14 at 18:14

2 Answers2

8

Here's what I'd do (I'm actually considering writing this library after seeing your question. I need it too):

Create a taskpool module with the following API.

client_id, token = taskpool.get()

# Setup a heartbeat in the client JS, maybe every minute. 
# Also call this every time the client indicates presence
taskpool.ping(client_id)

taskpool.release(client_id)

Implementation:

  • Store the client_id and token in an entity, with a status indicating whether it's being used, last ping time, and creation time. Let the client_id be the key. Also consider using NDB. Free memcaching.

get() checks if there are unused tokens and returns one if it finds it. Otherwise create a new one, store and return it.

ping() updates the last ping time for that token. Instead of polling, let the client send in a ping every [heartbeat] time.

release() marks the token as unused.

Run a task / cron every [heartbeat] seconds to find the tokens which haven't gotten a ping in a while - and set them as unused.

When clients report a closed token, perform a get().

Keep in mind, though, that a loss in security is a by-product of any kind of token pooling. If a malicious client has held on to a token and stopped sending heartbeats, it might later be able to listen in on the messages being passed to the new client once the token is re-purposed. This isn't a problem if you're on a fully public site, but keep it in mind anyway.

I will update this answer if and when I write this up as a library.

Sudhir Jonathan
  • 16,998
  • 13
  • 66
  • 90
  • Thanks for the creative answer Sudhir, but what is NDB? As far I know the existing App Engine Memcache API was free already? This definitely sounds like a viable, fully-featured solution, but I'd be very curious to see these how these multiple moving parts (crons/tasks and datastore operations) perform in action. Please let us know if you do wind up starting a library (especially if you open up an open-source repository :) ). – Eternal Rubyist Dec 22 '11 at 14:42
  • NDB is the new datastore API that's in 1.6.0 onwards:http://code.google.com/p/appengine-ndb-experiment/. Updated the answer with a link. – Sudhir Jonathan Dec 23 '11 at 05:46
  • Oh, and by 'free memcaching' I meant NDB takes care of caching for you. No extra lines of code. – Sudhir Jonathan Dec 23 '11 at 05:47
  • Ah I see. I may wind up implementing "Channel Pooling" library the way you described, but using Java rather than Python (as my application makes use of Google's GWT so a Python library wouldn't be feasible for my purposes). If I do, I'll update this question with a link to the forthcoming repo. – Eternal Rubyist Jan 01 '12 at 04:35
  • 1
    Sounds good... I also realized that the Channel API now provides presence handlers - they should make it much easier to track releases. – Sudhir Jonathan Jan 01 '12 at 07:57
  • Just as the last comment said, having presence handlers for comments makes much easier to track channel disconnections; i seem to have implemented a basic form of channel polling that stores clientIds and tokens on the datastore in a couple of hours – Raibaz Jan 04 '12 at 21:30
  • @Raibaz is it open source? A lot of folks seem to want this. – Sudhir Jonathan Jan 05 '12 at 05:46
  • haven't opensourced it yet as i still have to figure out some quirks, hopefully will release sometime in the future – Raibaz Jan 31 '12 at 08:56
2

According to the Google App Engine support team, channel tokens may not be reused. Reusing them is not expected to work.

Can Google App Engine Channels be reused?

Community
  • 1
  • 1
er0
  • 1,746
  • 2
  • 16
  • 31