2013-10-23 18 views
9

Sto utilizzando Flask per creare la mia applicazione web e vorrei registrare una risorsa globale che rappresenta una connessione a un servizio remoto che dura più a lungo di una richiesta (in questo caso, la connessione è una connessione SOAP che può essere valida per un massimo di 30 giorni).Flask long life global resources

Un altro esempio potrebbe essere un database come MongoDB che gestisce il pool di connessioni nel driver e si comporterebbe male se si creava una nuova connessione su ogni richiesta.

Né il contesto dell'applicazione né il contesto di richiesta sembrano appropriati per questa attività.

La domanda "Pass another object to the main flask application" suggerisce che memorizziamo tali risorse sul dizionario app.config.

+1

Perché il contesto dell'applicazione non sembra appropriato? – delnan

+0

Trovo che la documentazione in quest'area sia confusa. Vorrei configurazione queste connessioni in fase di creazione delle applicazioni, ma non riesco a trovare un modo nell'API di farlo. Puoi fornire un esempio? – idbentley

+1

Utilizzare il contesto dell'applicazione. L'esatto caso d'uso che citi è dimostrato nel [docs] (http://flask.pocoo.org/docs/appcontext/) –

risposta

3

Se DEVE coincidere con l'istanza della tua app, allora dovresti creare una sottoclasse di Flask. Questo in realtà non fa molto se tutto ciò che fai è collegare una risorsa all'oggetto, considerando che la creazione dell'app è un processo. La verità è che probabilmente non hai bisogno di farlo se l'applicazione non ha bisogno di usare la tua risorsa durante l'istanziazione.

class MyApp(Flask): 
    def __init__(self, *args, **kwargs): 
     setattr(self, 'some_resource', SomeResource()) 
     super(Flask, self).__init__(*args, **kwargs) 

app = MyApp(__name__) 
app.some_resource.do_something() 

A meno che non si dispone di alcuni casi uso specifico, si sono probabilmente meglio a scrivere una classe wrapper, trasformandolo in un pallone-estensione, creando sul livello di modulo e la memorizzazione su app.extensions.

class MyExtensions(object): 
    def __init__(self, app=None): 
     self.app = app 
     if app is not None: 
      self.init_app(app) 

    def init_app(self, app): 
     app.extensions['my_extension'] = SomeResource() 

app = Flask(__name__) 
my_extension = MyExtension(app) 

Poi si può scegliere se si vuole dare ad ogni applicazione la propria risorsa (come sopra), o se si preferisce utilizzare una risorsa condivisa che è sempre rivolta alla applicazione corrente

from flask import _request_ctx_stack 
try: 
    from flask import _app_ctx_stack 
except ImportError: 
    _app_ctx_stack = None 

stack = _app_ctx_stack or _request_ctx_stack 

class SomeResource(object): 
    def do_something(self): 
     ctx = stack.top 
     app = ctx.app 
my_resource = SomeResource() 
my_resource.do_something() 

non credo che si desidera memorizzare questo sul contesto applicativo, perché "inizia quando l'oggetto viene creata un'istanza Flask, e termina implicitamente quando la prima richiesta è disponibile in"

Invece, si vuole la vostra risorsa creato il il livello del modulo. Quindi puoi allegarlo all'applicazione come estensione, o sì, anche nella configurazione, anche se sarebbe più coerente e logico fare un'estensione veloce.

+0

IMO 'current_app.extensions ['my_extension']' è l'approccio migliore. – zengr

+1

È prassi comune condividere una connessione di database tra richieste. Ma penso che la documentazione sul sito web di Flask sia molto fuorviante. In realtà, le connessioni al database saranno stabilite per ogni richiesta come descritto qui. http://flask.pocoo.org/docs/0.10/appcontext/ – hanson

0

Questo è un problema di Python, la ragione Flask e altri framework web non permettono questo/rendere molto difficile è perché non esiste un modello di memoria definito per la concorrenza. Per esempio. supponiamo che il tuo server web serva le richieste nei loro processi (ad esempio Gunicorn). Ciò si tradurrà in processi che cancellano il processo principale e quindi copiano la variabile "globale". Se si esegue un server su Windows poi a causa della mancanza di una forchetta sarà invece fare un nuovo processo che reimporta tutti i moduli, probabilmente producendo una versione pulita del tuo stato globale che non ricorda tutte le modifiche apportate ad esso nel processo principale di pre -filo. O non trovarlo affatto se lo dichiari dietro un name guard.

Ci sono solo due modi possibili per fare costantemente questo "giusto". Uno è quello di costruire una webapp appositamente per mantenere il tuo stato globale e che è limitato a un singolo thread, e avere il tuo altro stato di chiamata webapp da questa webapp.

Il secondo, è utilizzare i thread Jython +. Dal momento che Jython viene eseguito in una JVM ha un modello di memoria ben definito con lo stato condiviso, in modo da poter utilizzare tutti i trucchi Java EE come contenitore concorrenza gestito ....