Processes
Run the app as stateless processes that share nothing, and keep anything that must last in a backing service.
Execute the app as one or more stateless processes. A process may use its memory and disk while handling one request, but must never count on finding anything there later. The next request may go to a different process, and this one may be restarted at any moment.
Anything that has to last, like users, carts, counters and sessions, belongs in a backing service.
#What goes wrong with state in memory
A visit counter, kept in a global variable:
from flask import Flask
app = Flask(__name__)
visits = 0 # lives in this process's memory only
@app.get("/")
def index():
global visits
visits += 1
return f"Visits: {visits}"With one process, it works. Run two behind a load balancer, and each keeps its own count:
1.First request
The load balancer sends it to web.1, which counts 1.
import os
import redis
from flask import Flask
app = Flask(__name__)
store = redis.Redis.from_url(os.environ["REDIS_URL"])
@app.get("/")
def index():
return f"Visits: {store.incr('visits')}"INCR is atomic, so two processes adding at the same moment never lose a visit.
#Sessions and sticky sessions
Logged-in sessions are state too. Store them in Redis or a database, or in a signed cookie, so any process can read them.
Sticky sessions, where the load balancer always sends a user to the same process, hide the problem instead of fixing it: the session still disappears when that process restarts. The twelve-factor rule is to never depend on them.
Referenced by