python - Werkzeug and class state with Flask: How are class member variables resetting when the class isn't being reinitialized? -


i'm trying write flask extension needs persist information between requests. works fine when run werkzeug single process when run multiple processes odd behavior don't understand. take simple application example:

from flask import flask app = flask(__name__)  class counter(object):     def __init__(self, app):         print('initializing counter object')         self.app = app         self.value = 0      def increment(self):         self.value += 1         print('just incremented, current value ', self.value)  counter = counter(app)  @app.route('/') def index():     in range(4):         counter.increment()     return 'index'  if __name__ == '__main__':     #scenario 1 - single process     #app.run()     #scenario 2 - threaded     #app.run(threaded=true)     #scenario 3 - 2 processes     app.run(processes=2) 

for first 2 scenarios behaves expect: counter object initialized once , increments every request '/' route. when run third scenario (passing processes=2) output:

 initializing counter object   * running on http://127.0.0.1:5000/ (press ctrl+c quit)  incremented, current value  1  incremented, current value  2  incremented, current value  3  incremented, current value  4  127.0.0.1 - - [30/aug/2015 09:47:25] "get / http/1.1" 200 -  incremented, current value  1  incremented, current value  2  incremented, current value  3  incremented, current value  4  127.0.0.1 - - [30/aug/2015 09:47:26] "get / http/1.1" 200 -  incremented, current value  1  incremented, current value  2  incremented, current value  3  incremented, current value  4  127.0.0.1 - - [30/aug/2015 09:47:27] "get / http/1.1" 200 - 

it seems counter.value returning it's state right after being initialized without being re-initialized. shed light on werkzeug doing internally make happen? i'd interested in learning if there way make behave naively expect (two processes, each own instance of counter). thanks!

the first example (single thread) uses 1 counter, works.

the second example (multiple threads), threads spawned handle each request. share memory 1 counter created before spawn, incrementing them each increments same thing.

the last example (multiple processes), processes spawned handle each request. flask's dev server uses fork: each child sees same starting point (counter initialized) increments in own address space goes away when request ends.

import os  class counter:     def __init__(self):         print('init')         self.value = 0      def increment(self):         self.value += 1         print('inc -> {}'.format(self.value))  counter = counter()  def multi():     if not os.fork():         # child starts copy of parent memory         _ in range(3):             # increments 3 times             counter.increment()          # child done         os._exit(0)  # 3 processes run _ in range(3):     multi() 
init inc -> 1 inc -> 2 inc -> 3 inc -> 1 inc -> 2 inc -> 3 inc -> 1 inc -> 2 inc -> 3 

use database or other external storage store global state across processes, using before_ , after_request. note it's not straightforward, since you'll have make storing incremented value of counter each request thread-safe, 2 threads don't overwrite value @ same time.

req 1 starts, gets stored value = 4 req 2 starts, gets stored value = 4 req 1 increments, value = 8 req 1 saves, value = 8 req 2 increments, value = 8 req 2 saves, value = 8 should = 12 

Comments

Popular posts from this blog

c# - Binding a comma separated list to a List<int> in asp.net web api -

Delphi 7 and decode UTF-8 base64 -

html - Is there any way to exclude a single element from the style? (Bootstrap) -