Reputation: 2299
I have a problem to achieve the following in Flask and SQLAlchemy: I have a kind of blog application written in Flask where a user can write textblocks. So I have a user model and a textblock model and the textblocks need to be kind of unique. Textblocks can be written and sent from two different client applications and that can happpen at the same time. I need to make the insertion and processing of the timeblock atomic so that the same timeblock is not inserted and processed at the same time by the two client-applications. The models:
class TextblockModel(db.Model):
__tablename__ = "textblock"
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
text = db.Column(db.Text, default="", nullable=False)
user = db.relationship("User", backref=db.backref("texts", lazy=True))
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), nullable=False)
email = db.Column(db.String(100), unique=True, nullable=False)
password = db.Column(db.String(255))
For each of the two client applications, I have one post endpoint:
def post1(self):
blocks = insert_block_into_db(request.json, current_user, CLIENTAPP1)
process_blocks(blocks)
def post2(self):
blocks = insert_block_into_db(request.json, current_user, CLIENTAPP2)
process_blocks(blocks)
I need to make the insertion and processing of textblocks atomic. So something like this:
def post1(self):
with lock:
blocks = insert_block_into_db(request.json, current_user, WEBAPP1)
process_blocks(blocks)
def post2(self):
with lock:
blocks = insert_block_into_db(request.json, current_user, WEBAPP2)
process_blocks(blocks)
But I think a plain Python lock doesn't work since WSGI spawns multiple processes for request-handling. Further, I don't need to lock everything but only the rows that are related to the current user. Does anyone have an idea how I could solve that?
Upvotes: 0
Views: 1730
Reputation: 766
If you are using gunicorn, then you can set preload_app = True
in your gunicorn.conf
. This ensures that a lock is shared across workers (i.e. processes).
A more webserver agnostic solution would be to use NamedAtomicLock. This is a great package that creates an operating system global lock. So a lock can be shared across processes. A lock creates an empty folder in a specified directory which is used as shared resource. Since creating and deleting direcories is an atomic operation according to the POSIX standard, this mechanism allows to lock across processes. I am not sure if it works on non-UNIX machines, e.g. Windows.
Upvotes: 1