4

I have a Python application deployed on Google Cloud Platform. There is a Google Cloud Datastore in the background, with two Kinds. I use NDB to pull the data into the application.

class AttEvent(ndb.Model):
  event = ndb.StringProperty()
  matchdate = ndb.DateTimeProperty()

class MainPage(webapp2.RequestHandler):

  def get(self):

    query = AttEvent.query().order(AttEvent.matchdate)
    for q in query.fetch():
        try:
          # application code

One of the Kinds (AtEvent in the code above) is causing me trouble. The app will deploy and work as expected for hours / days, but then intermittently stop returning data. Debugging shows the q object is legitimate object of the type AttEvent, but for each of the items in the values collection, it says "(Object has no fields)". When the application code attempts to reference a property of the model (i.e. q.event), it fails.

The query will suddenly start working again, minutes / hours later, even if I take no action. I can't see any pattern or apparent cause. Obviously this isn't ideal from a user perspective.

The Kind that is causing trouble is static data and only actually contains 3 entities. The other Kind is transactional, contains thousands of records, but has never exhibited the same behaviour.

The intermittent nature of the fault leads me to believe this is something to do with caching, but I am fairly new to Python and GCP, so I am not exactly sure. I've tried doing a context.clear_cache() before the query, but it has no effect.

Am I missing something obvious?

  • That is strange. Is there any correlation between changes to AttEvent entities and the error occurring? Or does the error happen long after any AttEvent entity has been created or changed? – new name Sep 08 '18 at 13:08
  • Hi Jeff. No correlation. It's done it again today, but I haven't made any updates to AttEvent entities for days. – John Ferguson Sep 08 '18 at 16:14

1 Answers1

2

I don't know why this is happening, but I have a possible work around. Since the data is static and the entities seem to be small, you could store them in instance memory instead of querying for them every time you need them.

Store the entities in a module level variable like this:

att_entities = AttEvent.query().order(AttEvent.matchdate).fetch()

class AttEvent(ndb.Model):
  event = ndb.StringProperty()
  matchdate = ndb.DateTimeProperty()

class MainPage(webapp2.RequestHandler):

  def get(self):
    for q in att_entities:
        try:
          # application code

You would get the entities only when a new instance is launched so as long as it works the first time you are all set. As a bonus, it will make the get call faster since you don't need to retrieve the data from the data store.

You might need to add extra logic to cause att_entities to be updated as needed.

new name
  • 15,861
  • 19
  • 68
  • 114
  • Thanks Jeff. I have published the changes and it seems to be working for now. I will let it run for a few days and see if it holds. Assuming it does, I might add a command-line parameter to the page, i.e. "forcerefresh=true" in order to trigger an update of the module-level variable. – John Ferguson Sep 08 '18 at 17:56
  • How would this solve the problem? If this instance's query is bad, then it will persist until the instance is shut down or a script refreshes. There must be something else going on. – GAEfan Sep 08 '18 at 22:59
  • @GAEfan, you are right, it doesn't fix the root cause, but because the error happens infrequently, as long as the query works the first time, it will prevent the error from happening for the lifetime of the instance. Also, even if the error is otherwise fixed, this could be a better implementation for him. – new name Sep 09 '18 at 12:27
  • @GAEfan / Jeff - I do appreciate the workaround, it's given me some stability and an assurance that my users are not suddenly seeing a blank screen. But I agree, I would like to get to the bottom of why it's happening in the first place, if nothing else, to ensure it's not me doing something stupid. – John Ferguson Sep 10 '18 at 08:51