mirror of
https://github.com/suitenumerique/meet.git
synced 2026-07-26 11:58:53 +00:00
⚡️(backend) change db state instead of using long running row lock
When analysing a file, the previous commit introduced a row level lock to make sure we would analyse and promote a single file. This commit changes the locking mechanism so that it happens with the upload state which avoids long running db locks and potential perf issues.
This commit is contained in:
@@ -1197,22 +1197,25 @@ class FileViewSet(
|
||||
Check the actual uploaded file and mark it as ready.
|
||||
"""
|
||||
# Ensures we go through authorization checks
|
||||
self.get_object()
|
||||
file = self.get_object()
|
||||
|
||||
# Try to update the file with the new state. If the file is already in this state
|
||||
# we are in a concurrent request, and we should reject that request
|
||||
updated_rows = models.File.objects.filter(
|
||||
upload_state=models.FileUploadStateChoices.PENDING,
|
||||
pk=kwargs["pk"],
|
||||
).update(upload_state=models.FileUploadStateChoices.ANALYZING)
|
||||
if updated_rows != 1:
|
||||
raise drf_exceptions.ValidationError(
|
||||
{"file": "This action is only available for files in PENDING state."},
|
||||
code="file_upload_state_not_pending",
|
||||
)
|
||||
file.refresh_from_db()
|
||||
|
||||
s3_client = default_storage.connection.meta.client
|
||||
validation_error = None
|
||||
|
||||
with transaction.atomic():
|
||||
file = self.get_queryset().select_for_update().get(pk=kwargs["pk"])
|
||||
|
||||
if not file.is_pending_upload:
|
||||
raise drf_exceptions.ValidationError(
|
||||
{
|
||||
"file": "This action is only available for files in PENDING state."
|
||||
},
|
||||
code="file_upload_state_not_pending",
|
||||
)
|
||||
|
||||
try:
|
||||
# We copy the file to its final destination, we will run the checks on that
|
||||
# final file and ignore any updates to the temporary file. (We cannot revoke the policy,
|
||||
# so the temporary file might still be updated after that.)
|
||||
@@ -1302,6 +1305,11 @@ class FileViewSet(
|
||||
Metadata=head_response["Metadata"],
|
||||
MetadataDirective="REPLACE",
|
||||
)
|
||||
except Exception as e:
|
||||
logger.exception("Failed to analyze file, reverting to pending state")
|
||||
file.upload_state = models.FileUploadStateChoices.PENDING
|
||||
file.save()
|
||||
raise e
|
||||
|
||||
if validation_error:
|
||||
raise validation_error
|
||||
@@ -1318,7 +1326,7 @@ class FileViewSet(
|
||||
"""Delete a file completely."""
|
||||
file.soft_delete()
|
||||
file.hard_delete()
|
||||
transaction.on_commit(lambda: process_file_deletion.delay(file.id))
|
||||
process_file_deletion.delay(file.id)
|
||||
|
||||
def _authorize_subrequest(self, request, pattern):
|
||||
"""
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.14 on 2026-06-02 12:47
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0018_rename_active_application_is_active'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='file',
|
||||
name='upload_state',
|
||||
field=models.CharField(choices=[('pending', 'Pending'), ('analyzing', 'Analyzing'), ('ready', 'Ready')], max_length=25),
|
||||
),
|
||||
]
|
||||
@@ -846,8 +846,8 @@ class FileUploadStateChoices(models.TextChoices):
|
||||
"""Possible states of a file."""
|
||||
|
||||
PENDING = "pending", _("Pending")
|
||||
ANALYZING = "analyzing", _("Analyzing")
|
||||
# Commented out for now, as we may need this when we implement the malware detection logic.
|
||||
# ANALYZING = "analyzing", _("Analyzing")
|
||||
# SUSPICIOUS = "suspicious", _("Suspicious")
|
||||
# FILE_TOO_LARGE_TO_ANALYZE = (
|
||||
# "file_too_large_to_analyze",
|
||||
|
||||
Reference in New Issue
Block a user