Resolves problems in storing/restoring tickerhandler keys. Resolves #997.
This commit is contained in:
parent
b014df00de
commit
03ef093d36
2 changed files with 37 additions and 26 deletions
|
|
@ -352,20 +352,21 @@ class TickerHandler(object):
|
||||||
shutdown or not.
|
shutdown or not.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
isdb_and_store_key (tuple): A tuple `(obj, path, interval,
|
store_key (tuple): A tuple `(packed_obj, methodname, outpath, interval,
|
||||||
methodname, idstring)` that uniquely identifies the
|
idstring, persistent)` that uniquely identifies the
|
||||||
ticker. `path` is `None` and `methodname` is the name of
|
ticker. Here, `packed_obj` is the unique string representation of the
|
||||||
the method if `obj_or_path` is a database object.
|
object or `None`. The `methodname` is the string name of the method on
|
||||||
Vice-versa, `obj` and `methodname` are `None` if
|
`packed_obj` to call, or `None` if `packed_obj` is unset. `path` is
|
||||||
`obj_or_path` is a python-path.
|
the Python-path to a non-method callable, or `None`. Finally, `interval`
|
||||||
|
`idstring` and `persistent` are integers, strings and bools respectively.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
interval = int(interval)
|
interval = int(interval)
|
||||||
persistent = bool(persistent)
|
persistent = bool(persistent)
|
||||||
outobj = pack_dbobj(obj)
|
packed_obj = pack_dbobj(obj)
|
||||||
outpath = path if path and isinstance(path, basestring) else None
|
|
||||||
methodname = callfunc if callfunc and isinstance(callfunc, basestring) else None
|
methodname = callfunc if callfunc and isinstance(callfunc, basestring) else None
|
||||||
return (outobj, methodname, outpath, interval, idstring, persistent)
|
outpath = path if path and isinstance(path, basestring) else None
|
||||||
|
return (packed_obj, methodname, outpath, interval, idstring, persistent)
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -382,14 +383,15 @@ class TickerHandler(object):
|
||||||
|
|
||||||
# remove any subscriptions that lost its object in the interim
|
# remove any subscriptions that lost its object in the interim
|
||||||
to_save = {store_key: (args, kwargs) for store_key, (args, kwargs) in self.ticker_storage.items()
|
to_save = {store_key: (args, kwargs) for store_key, (args, kwargs) in self.ticker_storage.items()
|
||||||
if inspect.ismethod(store_key[1]) and (not "_obj" in kwargs or kwargs["_obj"].pk)}
|
if ((store_key[1] and ("_obj" in kwargs and kwargs["_obj"].pk) and
|
||||||
|
hasattr(kwargs["_obj"], store_key[1])) or # a valid method with existing obj
|
||||||
|
store_key[2])} # a path given
|
||||||
|
|
||||||
# update the timers for the tickers
|
# update the timers for the tickers
|
||||||
for store_key, (args, kwargs) in to_save.items():
|
for store_key, (args, kwargs) in to_save.items():
|
||||||
interval = store_key[1]
|
interval = store_key[1]
|
||||||
# this is a mutable, so it's updated in-place in ticker_storage
|
# this is a mutable, so it's updated in-place in ticker_storage
|
||||||
kwargs["_start_delay"] = start_delays.get(interval, None)
|
kwargs["_start_delay"] = start_delays.get(interval, None)
|
||||||
kwargs.pop("_obj", None)
|
|
||||||
ServerConfig.objects.conf(key=self.save_name, value=dbserialize(to_save))
|
ServerConfig.objects.conf(key=self.save_name, value=dbserialize(to_save))
|
||||||
else:
|
else:
|
||||||
# make sure we have nothing lingering in the database
|
# make sure we have nothing lingering in the database
|
||||||
|
|
@ -413,22 +415,22 @@ class TickerHandler(object):
|
||||||
# the dbunserialize will convert all serialized dbobjs to real objects
|
# the dbunserialize will convert all serialized dbobjs to real objects
|
||||||
|
|
||||||
restored_tickers = dbunserialize(restored_tickers)
|
restored_tickers = dbunserialize(restored_tickers)
|
||||||
ticker_storage = {}
|
self.ticker_storage = {}
|
||||||
for store_key, (args, kwargs) in restored_tickers.iteritems():
|
for store_key, (args, kwargs) in restored_tickers.iteritems():
|
||||||
try:
|
try:
|
||||||
|
# at this point obj is the actual object (or None) due to how
|
||||||
|
# the dbunserialize works
|
||||||
obj, callfunc, path, interval, idstring, persistent = store_key
|
obj, callfunc, path, interval, idstring, persistent = store_key
|
||||||
if not persistent and not server_reload:
|
if not persistent and not server_reload:
|
||||||
# this ticker will not be restarted
|
# this ticker will not be restarted
|
||||||
continue
|
continue
|
||||||
if inspect.ismethod(callfunc) and not obj:
|
if isinstance(callfunc, basestring) and not obj:
|
||||||
|
# methods must have an existing object
|
||||||
continue
|
continue
|
||||||
if obj:
|
# we must rebuild the store_key here since obj must not be
|
||||||
try:
|
# stored as the object itself for the store_key to be hashable.
|
||||||
obj = unpack_dbobj(obj)
|
store_key = self._store_key(obj, path, interval, callfunc, idstring, persistent)
|
||||||
except IndexError:
|
|
||||||
# this happens with an old save, where obj was
|
|
||||||
# saved as itself; we must re-do the store_key.
|
|
||||||
store_key = self._store_key(obj, path, interval, callfunc, idstring, persistent)
|
|
||||||
if obj and callfunc:
|
if obj and callfunc:
|
||||||
kwargs["_callback"] = callfunc
|
kwargs["_callback"] = callfunc
|
||||||
kwargs["_obj"] = obj
|
kwargs["_obj"] = obj
|
||||||
|
|
@ -437,12 +439,16 @@ class TickerHandler(object):
|
||||||
callback = variable_from_module(modname, varname)
|
callback = variable_from_module(modname, varname)
|
||||||
kwargs["_callback"] = callback
|
kwargs["_callback"] = callback
|
||||||
kwargs["_obj"] = None
|
kwargs["_obj"] = None
|
||||||
ticker_storage[store_key] = (args, kwargs)
|
else:
|
||||||
except Exception as err:
|
# Neither object nor path - discard this ticker
|
||||||
|
log_err("Tickerhandler: Removing malformed ticker: %s" % str(store_key))
|
||||||
|
continue
|
||||||
|
except Exception:
|
||||||
# this suggests a malformed save or missing objects
|
# this suggests a malformed save or missing objects
|
||||||
log_err("%s\nTickerhandler: Removing malformed ticker: %s" % (err, str(store_key)))
|
log_trace("Tickerhandler: Removing malformed ticker: %s" % str(store_key))
|
||||||
continue
|
continue
|
||||||
self.ticker_storage = ticker_storage
|
# if we get here we should create a new ticker
|
||||||
|
self.ticker_storage[store_key] = (args, kwargs)
|
||||||
self.ticker_pool.add(store_key, *args, **kwargs)
|
self.ticker_pool.add(store_key, *args, **kwargs)
|
||||||
|
|
||||||
def add(self, interval=60, callback=None, idstring="", persistent=True, *args, **kwargs):
|
def add(self, interval=60, callback=None, idstring="", persistent=True, *args, **kwargs):
|
||||||
|
|
@ -481,11 +487,11 @@ class TickerHandler(object):
|
||||||
|
|
||||||
obj, path, callfunc = self._get_callback(callback)
|
obj, path, callfunc = self._get_callback(callback)
|
||||||
store_key = self._store_key(obj, path, interval, callfunc, idstring, persistent)
|
store_key = self._store_key(obj, path, interval, callfunc, idstring, persistent)
|
||||||
self.ticker_storage[store_key] = (args, kwargs)
|
|
||||||
self.save()
|
|
||||||
kwargs["_obj"] = obj
|
kwargs["_obj"] = obj
|
||||||
kwargs["_callback"] = callfunc # either method-name or callable
|
kwargs["_callback"] = callfunc # either method-name or callable
|
||||||
|
self.ticker_storage[store_key] = (args, kwargs)
|
||||||
self.ticker_pool.add(store_key, *args, **kwargs)
|
self.ticker_pool.add(store_key, *args, **kwargs)
|
||||||
|
self.save()
|
||||||
|
|
||||||
def remove(self, interval=60, callback=None, idstring="", persistent=True):
|
def remove(self, interval=60, callback=None, idstring="", persistent=True):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -278,6 +278,11 @@ def unpack_dbobj(item):
|
||||||
obj = item[3] and _TO_MODEL_MAP[item[1]].objects.get(id=item[3])
|
obj = item[3] and _TO_MODEL_MAP[item[1]].objects.get(id=item[3])
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
return None
|
return None
|
||||||
|
except TypeError:
|
||||||
|
if hasattr(item, "pk"):
|
||||||
|
# this happens if item is already an obj
|
||||||
|
return item
|
||||||
|
return None
|
||||||
# even if we got back a match, check the sanity of the date (some
|
# even if we got back a match, check the sanity of the date (some
|
||||||
# databases may 're-use' the id)
|
# databases may 're-use' the id)
|
||||||
return _TO_DATESTRING(obj) == item[2] and obj or None
|
return _TO_DATESTRING(obj) == item[2] and obj or None
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue