mirror of
https://github.com/zulip/zulip.git
synced 2025-11-01 20:44:04 +00:00
retention: Add flag to ArchiveTransaction to prevent automatic deletion.
This adds an index non-concurrently, but the table should be small enough for this to be fine.
This commit is contained in:
committed by
Tim Abbott
parent
bec0326776
commit
a352d35660
@@ -680,12 +680,20 @@ def clean_archived_data() -> None:
|
||||
# Associated archived objects will get deleted through the on_delete=CASCADE property:
|
||||
count = 0
|
||||
transaction_ids = list(
|
||||
ArchiveTransaction.objects.filter(timestamp__lt=check_date).values_list("id", flat=True)
|
||||
ArchiveTransaction.objects.filter(
|
||||
timestamp__lt=check_date, protect_from_deletion=False
|
||||
).values_list("id", flat=True)
|
||||
)
|
||||
while len(transaction_ids) > 0:
|
||||
transaction_block = transaction_ids[0:TRANSACTION_DELETION_BATCH_SIZE]
|
||||
transaction_ids = transaction_ids[TRANSACTION_DELETION_BATCH_SIZE:]
|
||||
ArchiveTransaction.objects.filter(id__in=transaction_block).delete()
|
||||
|
||||
ArchiveTransaction.objects.filter(
|
||||
# The protect_from_deletion=False condition is redundant at this point, but can act
|
||||
# as an extra safeguard against future bugs.
|
||||
id__in=transaction_block,
|
||||
protect_from_deletion=False,
|
||||
).delete()
|
||||
count += len(transaction_block)
|
||||
|
||||
logger.info("Deleted %s old ArchiveTransactions.", count)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# Generated by Django 5.0.10 on 2025-01-28 06:10
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("zerver", "0660_add_imageattachment_content_type"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="archivetransaction",
|
||||
name="protect_from_deletion",
|
||||
field=models.BooleanField(db_index=True, default=False),
|
||||
),
|
||||
]
|
||||
@@ -112,6 +112,10 @@ class ArchiveTransaction(models.Model):
|
||||
restored = models.BooleanField(default=False, db_index=True)
|
||||
restored_timestamp = models.DateTimeField(null=True, db_index=True)
|
||||
|
||||
# ArchiveTransaction objects are regularly deleted. This flag allows tagging
|
||||
# an ArchiveTransaction as protected from such automated deletion.
|
||||
protect_from_deletion = models.BooleanField(default=False, db_index=True)
|
||||
|
||||
type = models.PositiveSmallIntegerField(db_index=True)
|
||||
# Valid types:
|
||||
RETENTION_POLICY_BASED = 1 # Archiving was executed due to automated retention policies
|
||||
|
||||
@@ -952,24 +952,30 @@ class TestCleaningArchive(ArchiveMessagesTestingBase):
|
||||
self._make_expired_zulip_messages(7)
|
||||
archive_messages(chunk_size=2) # Small chunk size to have multiple transactions
|
||||
|
||||
transactions = list(ArchiveTransaction.objects.all())
|
||||
transactions = list(ArchiveTransaction.objects.all().order_by("id"))
|
||||
for transaction in transactions[0:-1]:
|
||||
transaction.timestamp = timezone_now() - timedelta(
|
||||
days=settings.ARCHIVED_DATA_VACUUMING_DELAY_DAYS + 1
|
||||
)
|
||||
transaction.save()
|
||||
|
||||
# This transaction would up for deletion, but we enable the flag preventing
|
||||
# it from automatic deletion:
|
||||
transactions[-2].protect_from_deletion = True
|
||||
transactions[-2].save()
|
||||
|
||||
message_ids_to_clean = list(
|
||||
ArchivedMessage.objects.filter(archive_transaction__in=transactions[0:-1]).values_list(
|
||||
ArchivedMessage.objects.filter(archive_transaction__in=transactions[0:-2]).values_list(
|
||||
"id", flat=True
|
||||
)
|
||||
)
|
||||
|
||||
clean_archived_data()
|
||||
remaining_transactions = list(ArchiveTransaction.objects.all())
|
||||
self.assert_length(remaining_transactions, 1)
|
||||
# All transactions except the last one were deleted:
|
||||
remaining_transactions = list(ArchiveTransaction.objects.order_by("-id"))
|
||||
self.assert_length(remaining_transactions, 2)
|
||||
# All transactions except the last two were deleted:
|
||||
self.assertEqual(remaining_transactions[0].id, transactions[-1].id)
|
||||
self.assertEqual(remaining_transactions[1].id, transactions[-2].id)
|
||||
# And corresponding ArchivedMessages should have been deleted:
|
||||
self.assertFalse(ArchivedMessage.objects.filter(id__in=message_ids_to_clean).exists())
|
||||
self.assertFalse(
|
||||
@@ -977,7 +983,10 @@ class TestCleaningArchive(ArchiveMessagesTestingBase):
|
||||
)
|
||||
|
||||
for message in ArchivedMessage.objects.all():
|
||||
self.assertEqual(message.archive_transaction_id, remaining_transactions[0].id)
|
||||
self.assertIn(
|
||||
message.archive_transaction_id,
|
||||
[remaining_transactions[0].id, remaining_transactions[1].id],
|
||||
)
|
||||
|
||||
|
||||
class TestGetRealmAndStreamsForArchiving(ZulipTestCase):
|
||||
|
||||
Reference in New Issue
Block a user