java - Multi Threading in Google App Engine Datastore -
how can make operations of getting , setting property datastore, thread safe?
currently, have code puts tasks in queue , each task perform task , updates property called of numberoftasks of type int. fetches current value of property , increments it.
however tasks executed in queue, final value not coming correct because of threading issue. sometimes, 2 tasks tries update proeprty @ same time , hence sometime increment isnt done.
could please in getting done correctly?
datastore property getter method:
private string doget(string rowid) throws entitynotfoundexception {     key egskey = keyfactory.createkey(datastore_kind, rowid);      entity egsentity = datastore.get(egskey);      // schema changed string text type. transparently handle here.     object propertyvalue = egsentity.getproperty(property_key);      if (propertyvalue instanceof string) {         return (string) propertyvalue;     }      text text = (text) propertyvalue;      return text.getvalue(); } datastore property setter method:
private void doput(string rowid, list<string> list) {     entity entity = new entity(datastore_kind, rowid);     entity.setproperty(property_key, list);      datastore.put(entity); } setter , getter methods:
public synchronized int getpendingusersforprocessing() {     string pendingusersforprocessingasstring = null;     try {         pendingusersforprocessingasstring = doget(pending_users_for_processing);         return integer.valueof(pendingusersforprocessingasstring);     } catch (numberformatexception e) {         throw new illegalstateexception("the num of last batches processed in datastore not number: "                 + pendingusersforprocessingasstring);     } catch (entitynotfoundexception e) {         return default_pending_users_for_processing;     } }  /** {@inheritdoc } */ @override public synchronized void setpendingusersforprocessing(int pendingusersforprocessing) {     doput(pending_users_for_processing, string.valueof(pendingusersforprocessing));     log.info("number of pending users processing set : " + pendingusersforprocessing); } code trying update property:
int pendingusers = appproperties.getpendingusersforprocessing(); int requestusers = request.getuserkeys().size(); appproperties.setpendingusersforprocessing(pendingusers + requestusers); 
this not threading issue may have multiple instances of app performing tasks, , instances not know each other. contention situation.
you have several options on how resolve it.
- use sharding counters. 
- instead of updating same entity, create new entity each completed task, using time when task completed id. advantage of approach creates audit trail , can stats number of tasks completed today, within last hour, etc. count number of entities can use keys-only query, free , fast. disadvantage higher cost of writing these entities - not solution if have large number of tasks complete. 
- instead of counting tasks, count results of these tasks. example, if task updates user status, can count number of users "pending" status using free , fast keys-only query. approach if have indexed property can use flag count tasks completed. 
Comments
Post a Comment