In the dev appserver with --high_replication, if I do this:

1. Create a blank entity
2. Edit that entity
3. put that entity
4. Generate a list of entities

That list, more often than not, shows me the blank entity.  The entity is in 
the index, but it does not reflect the put in step #3.  This is consistent with 
the "eventual consistency" model I've read about.

If, in step 4, I generate a list of all entity KEYS, and then db.get() those 
entities, I never see the blank entity.  This is also consistent with the 
documentation.

So, I believe that while my pattern requires an extra db roundtrip, it is much 
less like to show information that will lead to a support call.

-Joshua

On Sep 8, 2011, at 12:47 AM, Robert Kluin wrote:

> This is done on the backend, if I remember correctly.  It doesn't gain
> you anything.
> 
> 
> 
> On Wed, Sep 7, 2011 at 19:28, Joshua Smith <[email protected]> wrote:
>> Continuing the dialog with myself :)
>> 
>> I've added this method to one of my classes that extends db.Model() and it 
>> is working well with the dev appserver in --high_replication mode:
>> 
>>  @classmethod
>>  def gql_with_get(cls, query_string, *args, **kwds):
>>   return db.get(db.GqlQuery('SELECT __key__ FROM %s %s' % (cls.kind(), 
>> query_string), *args, **kwds))
>> 
>> You use it just like gql().fetch().  For example:
>> 
>>   boards = BoardModel.gql_with_get("WHERE towns = :1 ORDER BY name", tid)
>> 
>> It doesn't fix the index (things might be out of order, for instance), but 
>> otherwise, it cures the problem of seeing stale data in HR.
>> 
>> On Sep 7, 2011, at 12:22 PM, Joshua Smith wrote:
>> 
>>> Another thought: The reason I was doing only one meeting per request was 
>>> because of the old 30 second limit on crons.  But cron handlers can be 10 
>>> minutes now, which is plenty of time to schedule all the meetings.  
>>> Therefore, I suppose I could do this, right?
>>> 
>>>   now = datetime.datetime.now()
>>>   for schedule in db.get(db.gql("SELECT __key__ FROM ScheduleModel WHERE 
>>> next != :1 AND next < :2", None, now)):
>>>     if schedule.next and schedule.next < now:
>>>       schedule.cronAuto()
>>> 
>>> Is wrapping a GET around a KEYS-ONLY query guaranteed to get me the 
>>> real-deal results (except, of course, for the fact that the index might be 
>>> out-of-date, so I might miss recent changes to who is in/out of the query 
>>> parameters)?  Is this an efficient way to express this, or should I be 
>>> doing a fetch() on the gql first?
>>> 
>>> It seems like it's possible to use a technique like this to get a 
>>> more-consistent result in cases where that's desirable.  It at least would 
>>> get you a consistent data for a subset of things matching your query.  In 
>>> principle, you could even re-sort the results if there is an ORDER clause.  
>>> Seems like this would be something useful in the db API...
>>> 
>>> -Joshua
>>> 
>>> On Sep 7, 2011, at 11:18 AM, Joshua Smith wrote:
>>> 
>>>> 
>>>> I'm trying to port my existing M/S app to HR because I have a gun to my 
>>>> head with "Threaded Python Only for HR Apps" written on the bullets.
>>>> 
>>>> My system will schedule meetings automatically.  Scheduling a meeting can 
>>>> take some time, because a bunch of records are created, and a bunch of 
>>>> emails need to go out.  So the code to schedule one looked like this:
>>>> 
>>>> class MeetingAutoHandler(webapp.RequestHandler):
>>>> def get(self):
>>>>  schedule = ScheduleModel.gql("WHERE next != :1 AND next < :2", None, 
>>>> datetime.datetime.now()).get()
>>>>  if schedule:
>>>>    schedule.cronAuto()
>>>>    taskqueue.add(url='/admin/meetingAuto', method='GET', countdown=1)
>>>> 
>>>> The query looks for a schedule object that needs a meeting to to be 
>>>> scheduled now.  There might be a few of these when the cron runs.  So it 
>>>> does the hard work for one of them (in cronAuto()), and schedules another 
>>>> call to itself to get the next one using the task queue.
>>>> 
>>>> This isn't going to work in HR because that query is going to keep finding 
>>>> the same meeting.  I could trivially tweak this by setting the 
>>>> countdown=60, but I've yet to hear any of our google overlords commit to a 
>>>> maximum value of when "eventually" happens in "eventually consistent".  I 
>>>> presume there might be cases, like during data center transitions, when 
>>>> "eventually" could be a very long time indeed.  It is essentially 
>>>> unbounded.  Right?
>>>> 
>>>> But I like the pattern I'm using here, and I'm trying to change as little 
>>>> code as possible, so I want to put together a HR-resilient version.  
>>>> Here's what I came up with:
>>>> 
>>>> class MeetingAutoHandler(webapp.RequestHandler):
>>>> def get(self):
>>>>  now = datetime.datetime.now()
>>>>  for s in db.gql("SELECT __key__ FROM ScheduleModel WHERE next != :1 AND 
>>>> next < :2", None, now):
>>>>    schedule = db.get(s)
>>>>    if schedule.next and schedule.next < now:
>>>>      schedule.cronAuto()
>>>>      taskqueue.add(url='/admin/meetingAuto', method='GET', countdown=5)
>>>>      return
>>>> 
>>>> So I'm doing a keys-only query and then doing a get() on the key.  (I've 
>>>> never done a keys-only GQL query before, but I think I got it right.  Note 
>>>> to google: There should be an option to Model.gql() to do keys-only 
>>>> queries!)
>>>> 
>>>> The way I understand HR, that get is going to get the real Model, which 
>>>> might not meet the criteria in the gql, because the index might be out of 
>>>> date.  Right?
>>>> 
>>>> So I check that the model meets the criteria that I just specified.  (Note 
>>>> to google: It'd be cool if there was a way to test an object against a 
>>>> query, so I don't have to write the same code twice!)
>>>> 
>>>> Finally, I pushed the next task out a bit, to make it less likely that 
>>>> I'll have to look at the same objects over and over.
>>>> 
>>>> So what do you think?  Any suggestions?  (I have a couple things that work 
>>>> this way, so I want to choose a good design pattern to apply to each of 
>>>> them.)
>>>> 
>>>> The complexity would be lessened if I could to this:
>>>> 
>>>> class MeetingAutoHandler(webapp.RequestHandler):
>>>> def get(self):
>>>>  q = ScheduleModel.gql_keys_only("WHERE next != :1 AND next < :2", None,  
>>>> datetime.datetime.now())
>>>>  for s in  q:
>>>>    schedule = db.get(s)
>>>>    if q.matches(schedule):
>>>>      schedule.cronAuto()
>>>>      taskqueue.add(url='/admin/meetingAuto', method='GET', countdown=5)
>>>>      return
>>>> 
>>>> This would require two changes: the db.Model would need to support 
>>>> gql_keys_only (that's probably trivial); GqlQuery would need a matches() 
>>>> method (that's probably not trivial).
>>>> 
>>>> It's still a few more lines, but the complexity is about the same as the 
>>>> old one.
>>>> 
>>>> Worth the trouble of a couple feature request issues?
>>>> 
>>>> -Joshua
>>>> 
>>>> --
>>>> You received this message because you are subscribed to the Google Groups 
>>>> "Google App Engine" group.
>>>> To post to this group, send email to [email protected].
>>>> To unsubscribe from this group, send email to 
>>>> [email protected].
>>>> For more options, visit this group at 
>>>> http://groups.google.com/group/google-appengine?hl=en.
>>>> 
>>> 
>>> --
>>> You received this message because you are subscribed to the Google Groups 
>>> "Google App Engine" group.
>>> To post to this group, send email to [email protected].
>>> To unsubscribe from this group, send email to 
>>> [email protected].
>>> For more options, visit this group at 
>>> http://groups.google.com/group/google-appengine?hl=en.
>>> 
>> 
>> --
>> You received this message because you are subscribed to the Google Groups 
>> "Google App Engine" group.
>> To post to this group, send email to [email protected].
>> To unsubscribe from this group, send email to 
>> [email protected].
>> For more options, visit this group at 
>> http://groups.google.com/group/google-appengine?hl=en.
>> 
>> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "Google App Engine" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to 
> [email protected].
> For more options, visit this group at 
> http://groups.google.com/group/google-appengine?hl=en.
> 

-- 
You received this message because you are subscribed to the Google Groups 
"Google App Engine" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/google-appengine?hl=en.

Reply via email to