Search code examples
google-app-enginegoogle-cloud-datastoreapp-engine-ndbgoogle-app-engine-python

Why does dev_appserver.py exit without throwing errors?


I am trying to run a simple python 2 server code with AppEngine and Datastore. When I run dev_appserver.py app.yaml, the program immediately exits (without an error) after the following outputs:

/home/username/google-cloud-sdk/lib/third_party/google/auth/crypt/_cryptography_rsa.py:22: CryptographyDeprecationWarning: Python 2 is no longer supported by the Python core team. Support for it is now deprecated in cryptography, and will be removed in the next release.
  import cryptography.exceptions
INFO     2022-12-20 11:59:41,931 devappserver2.py:239] Using Cloud Datastore Emulator.
We are gradually rolling out the emulator as the default datastore implementation of dev_appserver.
If broken, you can temporarily disable it by --support_datastore_emulator=False
Read the documentation: https://cloud.google.com/appengine/docs/standard/python/tools/migrate-cloud-datastore-emulator

INFO     2022-12-20 11:59:41,936 devappserver2.py:316] Skipping SDK update check.
INFO     2022-12-20 11:59:42,332 datastore_emulator.py:156] Starting Cloud Datastore emulator at: http://localhost:22325
INFO     2022-12-20 11:59:42,981 datastore_emulator.py:162] Cloud Datastore emulator responded after 0.648865 seconds
INFO     2022-12-20 11:59:42,982 <string>:384] Starting API server at: http://localhost:38915

Ideally, it should have continued by runnning the server on port 8000. Also, it works with option --support_datastore_emulator=False.

This is the code:

import webapp2
import datetime
from google.appengine.ext import db, deferred, ndb
import uuid
from base64 import b64decode, b64encode
import logging


class Email(ndb.Model):
    email = ndb.StringProperty()

class DB(webapp2.RequestHandler):
    def post(self):
        try:
            mail = Email()
            mail.email = 'Test'
            mail.put()
        except Exception as e:
            print(e)
            self.response.headers['Content-Type'] = 'application/json; charset=utf-8'
            return self.response.out.write(e)
    
    def get(self):
        try:
            e1 = Email.query()
            logging.critical('count is: %s' % e1.count)
            e1k = e1.get(keys_only=True)
            logging.critical('count 2 is: %s' % e1k.count)
            e1 = e1.get()

            key = unicode(e1.key.urlsafe())
            logging.critical('This is a critical message: %s' % key)
            logging.critical('This is a critical message: %s' % e1k)

            e2 = ndb.Key(urlsafe=key).get()

            self.response.headers['Content-Type'] = 'application/json; charset=utf-8'
            return self.response.out.write(str(e2.email))
        except Exception as e:
            print(e)
            self.response.headers['Content-Type'] = 'application/json; charset=utf-8'
            return self.response.out.write(e)

app = webapp2.WSGIApplication([
    ('/', DB)
], debug=True)

How can I find the reason this is not working?

Edit: I figured that the dev server works and writes to a datastore even with support_datastore_emulator=False option. I am confused by this option. I also don't know where the database is stored currently.


Solution

    1. It should be count() and not count i.e.

      logging.critical('count is: %s' % e1.count())

    2. A get returns only 1 record and so it doesn't make sense to do a count after calling a get. Besides, the count operation is a method of the query instance not the results. This means the following code is incorrect

      e1k = e1.get(keys_only=True)
      logging.critical('count 2 is: %s' % e1k.count)
      
      

      You should replace it with

      elk = e1.fetch(keys_only=True) # fetch gives an array
      logging.critical('count 2 is: %s' % len(e1k))
      
      
    3. When you first run your App, it will execute the GET part of your code and because this is the first time your App is being run, you have no record in Datastore. This means e1 = e1.get() will return None and key = unicode(e1.key.urlsafe()) will lead to an error.

      You have to modify your code to first check you have a value for e1 or e2 before you attempt to use the keys.

    4. I ran your code with dev_appserver.py and it displayed these errors for me in the logs. But I ran it with an older version of gcloud SDK (Google Cloud SDK 367.0.0). I don't know why yours exited without displaying any errors. Maybe it's due to the version...??

    5. Separately - Don't know why you're importing db. Google moved on to ndb long ago and you don't use db in your code

    6. The default datastore (for the older generation runtimes like Python 2) is in .config (hidden folder) > gcloud > emulators > datastore

      You can also specify your own location by using the flag --datastore_path. See documentation