0

I'm trying to build a small and fast API with Flask and a global object that would be share in the application (each request could check this global object and search an ID). I don't want db, redis or other solution like that: I just want something easy to understand.

For example the code below: (with flask-restplus)

...
database = collections.defaultdict(int)

@ns.route('/')
class List(Resource):

  @ns.doc('list', description="Get id")
  def get(self):
     logger = logging.getLogger(__name__)
     database["TEST"] += 1
     logger.info(database["TEST"])
     return {"test": database["TEST"]}

2018-11-02 14:53:44,575 INFO       namespace:   48 -- 1
2018-11-02 14:53:44,712 INFO       _internal:   88 -- 127.0.0.1 - - [02/Nov/2018 14:53:44] "GET /workflow/ HTTP/1.1" 200 -
2018-11-02 14:53:44,720 INFO       namespace:   48 -- 2
2018-11-02 14:53:44,838 INFO       _internal:   88 -- 127.0.0.1 - - [02/Nov/2018 14:53:44] "GET /workflow/ HTTP/1.1" 200 -
2018-11-02 14:53:44,848 INFO       namespace:   48 -- 3
2018-11-02 14:53:44,935 INFO.      _internal:   88 -- 127.0.0.1 - - [02/Nov/2018 14:53:44] "GET /workflow/ HTTP/1.1" 200 -
2018-11-02 14:53:44,942 INFO       namespace:   48 -- 4
2018-11-02 14:53:45,044 INFO.      _internal:   88 -- 127.0.0.1 - - [02/Nov/2018 14:53:45] "GET /workflow/ HTTP/1.1" 200 -
2018-11-02 14:53:45,051 INFO.      namespace:   48 -- 5
2018-11-02 14:53:45,151 INFO.      _internal:   88 -- 127.0.0.1 - - [02/Nov/2018 14:53:45] "GET /workflow/ HTTP/1.1" 200 -
2018-11-02 14:53:45,158 INFO.      namespace:   48 -- 6
2018-11-02 14:53:45,256 INFO.      _internal:   88 -- 127.0.0.1 - - [02/Nov/2018 14:53:45] "GET /workflow/ HTTP/1.1" 200 -
2018-11-02 14:53:45,263 INFO.      namespace:   48 -- 7
2018-11-02 14:53:45,345 INFO.      _internal:   88 -- 127.0.0.1 - - [02/Nov/2018 14:53:45] "GET /workflow/ HTTP/1.1" 200 -
2018-11-02 14:53:45,360 INFO.      namespace:   48 -- 8
2018-11-02 14:53:45,469 INFO.      _internal:   88 -- 127.0.0.1 - - [02/Nov/2018 14:53:45] "GET /workflow/ HTTP/1.1" 200 -
2018-11-02 14:53:45,476 INFO.      namespace:   48 -- 9

It's working but I have few questions:

  • Flask is limited to one thread in the dev mode by default. I tried with the option threaded=3 and it was still working. I was lucky ? it's not safe to use a global variable like that in a multithreaded environment isn't it ?
  • I want my application to be small as possible: I don't want to use wsgi/redis/celery/... to handle many requests. But Flask seems to be designed to work only with a WSGI. Message I get when I launch Flask: WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. Can I use Flask with the development server for my production application ? Is it still a good practice ?
  • Maybe the conclusion it's I'm using the wrong web framework. Tornado is monothread and monoprocess by default which would solve all these problems. What do you think ? Am I wrong ?

Thanks for your help,

PakitoSec
  • 53
  • 1
  • 6

1 Answers1

0

1) That depends on how you're going to use this global variable, I suppose. The only thing is certain - you will have to take care of threads changing global state on your own. Concurrency issues are usually the nastiest issues you may ever meet. The worst thing about them that there's almost no way to test them out, only design them out. There's a nice article about the topic (this is for java, but I am sure same applies for python https://www.planetgeek.ch/2009/08/25/how-to-find-a-concurrency-bug-with-java/). Takeaway - globals will not simplify things. They will make things look simple, while make them as complex as hell.

2) Well, you can use development server for production usage, but why would you want that? Without knowing a context of the application you try to develop it is not possible to tell how reasonable it would be to use development server for that, but for most cases it is not feasible solution.

3) It all boils down to what your end goal is. If you want all-in-one framework, then Tornado is a way to go. That will not solve the issue with global variables, though (see this, for instance Tornado - Python global variable)

Alexander Pushkarev
  • 1,075
  • 6
  • 19