My web application posts multiple files (FileField) that is associated with the same item. For each item I make a directory for storing all the related files. However, when frontend sends a sequence of file posts to this model, I run into race condition in the filesystemstorage and have an error there.
When the first file is uploaded, the item directory is not existed yet and is going to make a directory. Then the second file also checks the item directory existence and trying to do the same directory creation. Then the thread switched to the first file upload and creates the directory. Then the second file upload it also creates the same directory and gets the creation error since the directory has been created by the first upload already. Here is my model definition.
what approach can I take to avoid this kind of race condition? maybe a fix on the django source code in core/files/storage.py line 236 in FileSystemStorage _save method could work?
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/rest_framework/serializers.py", line 214, in save
self.instance = self.create(validated_data)
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/rest_framework/serializers.py", line 940, in create
instance = ModelClass.objects.create(**validated_data)
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/db/models/query.py", line 413, in create
obj.save(force_insert=True, using=self.db)
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/db/models/base.py", line 717, in save
force_update=force_update, update_fields=update_fields)
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/db/models/base.py", line 747, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/db/models/base.py", line 830, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/db/models/base.py", line 868, in _do_insert
using=using, raw=raw)
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/db/models/query.py", line 1133, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1284, in execute_sql
for sql, params in self.as_sql():
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1237, in as_sql
for obj in self.query.objs
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1237, in <listcomp>
for obj in self.query.objs
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1236, in <listcomp>
[self.prepare_value(field, self.pre_save_val(field, obj)) for field in fields]
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 1188, in pre_save_val
return field.pre_save(obj, add=True)
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/db/models/fields/files.py", line 288, in pre_save
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/db/models/fields/files.py", line 87, in save
self.name = self.storage.save(name, content, max_length=self.field.max_length)
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/core/files/storage.py", line 49, in save
return self._save(name, content)
File "/Users/han/anaconda3/envs/django/lib/python3.6/site-packages/django/core/files/storage.py", line 236, in _save
os.makedirs(directory)
File "/Users/han/anaconda3/envs/django/lib/python3.6/os.py", line 220, in makedirs
mkdir(name, mode)
FileExistsError: [Errno 17] File exists: