diff --git a/api.py b/api.py index 0f46eed..235747a 100644 --- a/api.py +++ b/api.py @@ -27,10 +27,6 @@ from cosmopolite.lib import utils import config -class InvalidInstanceID(Exception): - pass - - def CreateChannel(google_user, client, instance_id, args): models.Instance.FindOrCreate(instance_id) @@ -84,7 +80,10 @@ def SendMessage(google_user, client, instance_id, args): def Subscribe(google_user, client, instance_id, args): instance = models.Instance.FromID(instance_id) if not instance or not instance.active: - raise InvalidInstanceID + # Probably a race with the channel opening + return { + 'result': 'retry', + } subject = models.Subject.FindOrCreate(args['subject']) messages = args.get('messages', 0) diff --git a/static/cosmopolite.js b/static/cosmopolite.js index f44017e..1db088b 100644 --- a/static/cosmopolite.js +++ b/static/cosmopolite.js @@ -469,7 +469,7 @@ Cosmopolite.prototype.sendRPCs_ = function(commands, delay) { var xhr = new XMLHttpRequest(); xhr.responseType = 'json'; - var retryAfterDelay = function() { + var retryAfterDelay = function(newCommands) { var intDelay = xhr.getResponseHeader('Retry-After') || Math.min(32, Math.max(2, delay || 2)); @@ -477,14 +477,14 @@ Cosmopolite.prototype.sendRPCs_ = function(commands, delay) { this.loggingPrefix_(), 'RPC failed; will retry in ' + intDelay + ' seconds'); var retry = function() { - this.sendRPCs_(commands, Math.pow(intDelay, 2)); + this.sendRPCs_(newCommands, Math.pow(intDelay, 2)); }.bind(this); window.setTimeout(retry, intDelay * 1000); }.bind(this); xhr.addEventListener('load', function(e) { if (xhr.status != 200) { - retryAfterDelay(); + retryAfterDelay(commands); return; } var data = xhr.response; @@ -517,11 +517,22 @@ Cosmopolite.prototype.sendRPCs_ = function(commands, delay) { // data. data['events'].forEach(this.onServerEvent_, this); + var retryCommands = []; + for (var i = 0; i < data['responses'].length; i++) { + var response = data['responses'][i]; + if (response['result'] == 'retry') { + retryCommands.push(commands[i]); + continue; + } if (commands[i]['onSuccess']) { commands[i]['onSuccess'].bind(this)(data['responses'][i]); } } + + if (retryCommands.length) { + retryAfterDelay(retryCommands); + } }.bind(this)); xhr.addEventListener('error', retryAfterDelay);