Honour the 'rejected' return from push gateways
Add a timestamp to push tokens so we know the last time they we got them from the device. Send it to the push gateways so it can determine whether its failure is more recent than the token. Stop and remove pushers that have been rejected.pull/27/head
parent
c06a9063e1
commit
2cb30767fa
|
@ -31,8 +31,8 @@ class Pusher(object):
|
||||||
GIVE_UP_AFTER = 24 * 60 * 60 * 1000
|
GIVE_UP_AFTER = 24 * 60 * 60 * 1000
|
||||||
|
|
||||||
def __init__(self, _hs, user_name, app_id,
|
def __init__(self, _hs, user_name, app_id,
|
||||||
app_display_name, device_display_name, pushkey, data,
|
app_display_name, device_display_name, pushkey, pushkey_ts,
|
||||||
last_token, last_success, failing_since):
|
data, last_token, last_success, failing_since):
|
||||||
self.hs = _hs
|
self.hs = _hs
|
||||||
self.evStreamHandler = self.hs.get_handlers().event_stream_handler
|
self.evStreamHandler = self.hs.get_handlers().event_stream_handler
|
||||||
self.store = self.hs.get_datastore()
|
self.store = self.hs.get_datastore()
|
||||||
|
@ -42,6 +42,7 @@ class Pusher(object):
|
||||||
self.app_display_name = app_display_name
|
self.app_display_name = app_display_name
|
||||||
self.device_display_name = device_display_name
|
self.device_display_name = device_display_name
|
||||||
self.pushkey = pushkey
|
self.pushkey = pushkey
|
||||||
|
self.pushkey_ts = pushkey_ts
|
||||||
self.data = data
|
self.data = data
|
||||||
self.last_token = last_token
|
self.last_token = last_token
|
||||||
self.last_success = last_success # not actually used
|
self.last_success = last_success # not actually used
|
||||||
|
@ -98,9 +99,31 @@ class Pusher(object):
|
||||||
|
|
||||||
processed = False
|
processed = False
|
||||||
if self._should_notify_for_event(single_event):
|
if self._should_notify_for_event(single_event):
|
||||||
processed = yield self.dispatch_push(single_event)
|
rejected = yield self.dispatch_push(single_event)
|
||||||
|
if not rejected == False:
|
||||||
|
processed = True
|
||||||
|
for pk in rejected:
|
||||||
|
if pk != self.pushkey:
|
||||||
|
# for sanity, we only remove the pushkey if it
|
||||||
|
# was the one we actually sent...
|
||||||
|
logger.warn(
|
||||||
|
("Ignoring rejected pushkey %s because we" +
|
||||||
|
"didn't send it"), (pk,)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
logger.info(
|
||||||
|
"Pushkey %s was rejected: removing",
|
||||||
|
pk
|
||||||
|
)
|
||||||
|
yield self.hs.get_pusherpool().remove_pusher(
|
||||||
|
self.app_id, pk
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
processed = True
|
processed = True
|
||||||
|
|
||||||
|
if not self.alive:
|
||||||
|
continue
|
||||||
|
|
||||||
if processed:
|
if processed:
|
||||||
self.backoff_delay = Pusher.INITIAL_BACKOFF
|
self.backoff_delay = Pusher.INITIAL_BACKOFF
|
||||||
self.last_token = chunk['end']
|
self.last_token = chunk['end']
|
||||||
|
@ -165,6 +188,14 @@ class Pusher(object):
|
||||||
self.alive = False
|
self.alive = False
|
||||||
|
|
||||||
def dispatch_push(self, p):
|
def dispatch_push(self, p):
|
||||||
|
"""
|
||||||
|
Overridden by implementing classes to actually deliver the notification
|
||||||
|
:param p: The event to notify for as a single event from the event stream
|
||||||
|
:return: If the notification was delivered, an array containing any
|
||||||
|
pushkeys that were rejected by the push gateway.
|
||||||
|
False if the notification could not be delivered (ie.
|
||||||
|
should be retried).
|
||||||
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,8 +25,8 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class HttpPusher(Pusher):
|
class HttpPusher(Pusher):
|
||||||
def __init__(self, _hs, user_name, app_id,
|
def __init__(self, _hs, user_name, app_id,
|
||||||
app_display_name, device_display_name, pushkey, data,
|
app_display_name, device_display_name, pushkey, pushkey_ts,
|
||||||
last_token, last_success, failing_since):
|
data, last_token, last_success, failing_since):
|
||||||
super(HttpPusher, self).__init__(
|
super(HttpPusher, self).__init__(
|
||||||
_hs,
|
_hs,
|
||||||
user_name,
|
user_name,
|
||||||
|
@ -34,6 +34,7 @@ class HttpPusher(Pusher):
|
||||||
app_display_name,
|
app_display_name,
|
||||||
device_display_name,
|
device_display_name,
|
||||||
pushkey,
|
pushkey,
|
||||||
|
pushkey_ts,
|
||||||
data,
|
data,
|
||||||
last_token,
|
last_token,
|
||||||
last_success,
|
last_success,
|
||||||
|
@ -77,6 +78,7 @@ class HttpPusher(Pusher):
|
||||||
{
|
{
|
||||||
'app_id': self.app_id,
|
'app_id': self.app_id,
|
||||||
'pushkey': self.pushkey,
|
'pushkey': self.pushkey,
|
||||||
|
'pushkeyTs': long(self.pushkey_ts / 1000),
|
||||||
'data': self.data_minus_url
|
'data': self.data_minus_url
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -87,10 +89,13 @@ class HttpPusher(Pusher):
|
||||||
def dispatch_push(self, event):
|
def dispatch_push(self, event):
|
||||||
notification_dict = self._build_notification_dict(event)
|
notification_dict = self._build_notification_dict(event)
|
||||||
if not notification_dict:
|
if not notification_dict:
|
||||||
defer.returnValue(True)
|
defer.returnValue([])
|
||||||
try:
|
try:
|
||||||
yield self.httpCli.post_json_get_json(self.url, notification_dict)
|
resp = yield self.httpCli.post_json_get_json(self.url, notification_dict)
|
||||||
except:
|
except:
|
||||||
logger.exception("Failed to push %s ", self.url)
|
logger.exception("Failed to push %s ", self.url)
|
||||||
defer.returnValue(False)
|
defer.returnValue(False)
|
||||||
defer.returnValue(True)
|
rejected = []
|
||||||
|
if 'rejected' in resp:
|
||||||
|
rejected = resp['rejected']
|
||||||
|
defer.returnValue(rejected)
|
||||||
|
|
|
@ -53,6 +53,7 @@ class PusherPool:
|
||||||
"app_display_name": app_display_name,
|
"app_display_name": app_display_name,
|
||||||
"device_display_name": device_display_name,
|
"device_display_name": device_display_name,
|
||||||
"pushkey": pushkey,
|
"pushkey": pushkey,
|
||||||
|
"pushkey_ts": self.hs.get_clock().time_msec(),
|
||||||
"data": data,
|
"data": data,
|
||||||
"last_token": None,
|
"last_token": None,
|
||||||
"last_success": None,
|
"last_success": None,
|
||||||
|
@ -75,6 +76,7 @@ class PusherPool:
|
||||||
app_display_name=app_display_name,
|
app_display_name=app_display_name,
|
||||||
device_display_name=device_display_name,
|
device_display_name=device_display_name,
|
||||||
pushkey=pushkey,
|
pushkey=pushkey,
|
||||||
|
pushkey_ts=self.hs.get_clock().time_msec(),
|
||||||
data=json.dumps(data)
|
data=json.dumps(data)
|
||||||
)
|
)
|
||||||
self._refresh_pusher((app_id, pushkey))
|
self._refresh_pusher((app_id, pushkey))
|
||||||
|
@ -88,6 +90,7 @@ class PusherPool:
|
||||||
app_display_name=pusherdict['app_display_name'],
|
app_display_name=pusherdict['app_display_name'],
|
||||||
device_display_name=pusherdict['device_display_name'],
|
device_display_name=pusherdict['device_display_name'],
|
||||||
pushkey=pusherdict['pushkey'],
|
pushkey=pusherdict['pushkey'],
|
||||||
|
pushkey_ts=pusherdict['pushkey_ts'],
|
||||||
data=pusherdict['data'],
|
data=pusherdict['data'],
|
||||||
last_token=pusherdict['last_token'],
|
last_token=pusherdict['last_token'],
|
||||||
last_success=pusherdict['last_success'],
|
last_success=pusherdict['last_success'],
|
||||||
|
@ -118,3 +121,12 @@ class PusherPool:
|
||||||
self.pushers[fullid].stop()
|
self.pushers[fullid].stop()
|
||||||
self.pushers[fullid] = p
|
self.pushers[fullid] = p
|
||||||
p.start()
|
p.start()
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def remove_pusher(self, app_id, pushkey):
|
||||||
|
fullid = "%s:%s" % (app_id, pushkey)
|
||||||
|
if fullid in self.pushers:
|
||||||
|
logger.info("Stopping pusher %s", fullid)
|
||||||
|
self.pushers[fullid].stop()
|
||||||
|
del self.pushers[fullid]
|
||||||
|
yield self.store.delete_pusher_by_app_id_pushkey(app_id, pushkey)
|
|
@ -30,7 +30,7 @@ class PusherStore(SQLBaseStore):
|
||||||
def get_pushers_by_app_id_and_pushkey(self, app_id_and_pushkey):
|
def get_pushers_by_app_id_and_pushkey(self, app_id_and_pushkey):
|
||||||
sql = (
|
sql = (
|
||||||
"SELECT id, user_name, kind, app_id,"
|
"SELECT id, user_name, kind, app_id,"
|
||||||
"app_display_name, device_display_name, pushkey, data, "
|
"app_display_name, device_display_name, pushkey, ts, data, "
|
||||||
"last_token, last_success, failing_since "
|
"last_token, last_success, failing_since "
|
||||||
"FROM pushers "
|
"FROM pushers "
|
||||||
"WHERE app_id = ? AND pushkey = ?"
|
"WHERE app_id = ? AND pushkey = ?"
|
||||||
|
@ -49,10 +49,11 @@ class PusherStore(SQLBaseStore):
|
||||||
"app_display_name": r[4],
|
"app_display_name": r[4],
|
||||||
"device_display_name": r[5],
|
"device_display_name": r[5],
|
||||||
"pushkey": r[6],
|
"pushkey": r[6],
|
||||||
"data": r[7],
|
"pushkey_ts": r[7],
|
||||||
"last_token": r[8],
|
"data": r[8],
|
||||||
"last_success": r[9],
|
"last_token": r[9],
|
||||||
"failing_since": r[10]
|
"last_success": r[10],
|
||||||
|
"failing_since": r[11]
|
||||||
}
|
}
|
||||||
for r in rows
|
for r in rows
|
||||||
]
|
]
|
||||||
|
@ -63,7 +64,7 @@ class PusherStore(SQLBaseStore):
|
||||||
def get_all_pushers(self):
|
def get_all_pushers(self):
|
||||||
sql = (
|
sql = (
|
||||||
"SELECT id, user_name, kind, app_id,"
|
"SELECT id, user_name, kind, app_id,"
|
||||||
"app_display_name, device_display_name, pushkey, data, "
|
"app_display_name, device_display_name, pushkey, ts, data, "
|
||||||
"last_token, last_success, failing_since "
|
"last_token, last_success, failing_since "
|
||||||
"FROM pushers"
|
"FROM pushers"
|
||||||
)
|
)
|
||||||
|
@ -79,10 +80,11 @@ class PusherStore(SQLBaseStore):
|
||||||
"app_display_name": r[4],
|
"app_display_name": r[4],
|
||||||
"device_display_name": r[5],
|
"device_display_name": r[5],
|
||||||
"pushkey": r[6],
|
"pushkey": r[6],
|
||||||
"data": r[7],
|
"pushkey_ts": r[7],
|
||||||
"last_token": r[8],
|
"data": r[8],
|
||||||
"last_success": r[9],
|
"last_token": r[9],
|
||||||
"failing_since": r[10]
|
"last_success": r[10],
|
||||||
|
"failing_since": r[11]
|
||||||
}
|
}
|
||||||
for r in rows
|
for r in rows
|
||||||
]
|
]
|
||||||
|
@ -91,7 +93,8 @@ class PusherStore(SQLBaseStore):
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def add_pusher(self, user_name, kind, app_id,
|
def add_pusher(self, user_name, kind, app_id,
|
||||||
app_display_name, device_display_name, pushkey, data):
|
app_display_name, device_display_name,
|
||||||
|
pushkey, pushkey_ts, data):
|
||||||
try:
|
try:
|
||||||
yield self._simple_upsert(
|
yield self._simple_upsert(
|
||||||
PushersTable.table_name,
|
PushersTable.table_name,
|
||||||
|
@ -104,12 +107,20 @@ class PusherStore(SQLBaseStore):
|
||||||
kind=kind,
|
kind=kind,
|
||||||
app_display_name=app_display_name,
|
app_display_name=app_display_name,
|
||||||
device_display_name=device_display_name,
|
device_display_name=device_display_name,
|
||||||
|
ts=pushkey_ts,
|
||||||
data=data
|
data=data
|
||||||
))
|
))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error("create_pusher with failed: %s", e)
|
logger.error("create_pusher with failed: %s", e)
|
||||||
raise StoreError(500, "Problem creating pusher.")
|
raise StoreError(500, "Problem creating pusher.")
|
||||||
|
|
||||||
|
@defer.inlineCallbacks
|
||||||
|
def delete_pusher_by_app_id_pushkey(self, app_id, pushkey):
|
||||||
|
yield self._simple_delete_one(
|
||||||
|
PushersTable.table_name,
|
||||||
|
dict(app_id=app_id, pushkey=pushkey)
|
||||||
|
)
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def update_pusher_last_token(self, user_name, pushkey, last_token):
|
def update_pusher_last_token(self, user_name, pushkey, last_token):
|
||||||
yield self._simple_update_one(
|
yield self._simple_update_one(
|
||||||
|
@ -147,6 +158,7 @@ class PushersTable(Table):
|
||||||
"app_display_name",
|
"app_display_name",
|
||||||
"device_display_name",
|
"device_display_name",
|
||||||
"pushkey",
|
"pushkey",
|
||||||
|
"pushkey_ts",
|
||||||
"data",
|
"data",
|
||||||
"last_token",
|
"last_token",
|
||||||
"last_success",
|
"last_success",
|
||||||
|
|
|
@ -21,6 +21,7 @@ CREATE TABLE IF NOT EXISTS pushers (
|
||||||
app_display_name varchar(64) NOT NULL,
|
app_display_name varchar(64) NOT NULL,
|
||||||
device_display_name varchar(128) NOT NULL,
|
device_display_name varchar(128) NOT NULL,
|
||||||
pushkey blob NOT NULL,
|
pushkey blob NOT NULL,
|
||||||
|
ts BIGINT NOT NULL,
|
||||||
data blob,
|
data blob,
|
||||||
last_token TEXT,
|
last_token TEXT,
|
||||||
last_success BIGINT,
|
last_success BIGINT,
|
||||||
|
|
|
@ -21,6 +21,7 @@ CREATE TABLE IF NOT EXISTS pushers (
|
||||||
app_display_name varchar(64) NOT NULL,
|
app_display_name varchar(64) NOT NULL,
|
||||||
device_display_name varchar(128) NOT NULL,
|
device_display_name varchar(128) NOT NULL,
|
||||||
pushkey blob NOT NULL,
|
pushkey blob NOT NULL,
|
||||||
|
ts BIGINT NOT NULL,
|
||||||
data blob,
|
data blob,
|
||||||
last_token TEXT,
|
last_token TEXT,
|
||||||
last_success BIGINT,
|
last_success BIGINT,
|
||||||
|
|
Loading…
Reference in New Issue