Skip to content

Commit d3fc534

Browse files
authored
chore(deletions): Move docs to README (#95598)
A Markdown file provides more options for richer text. [skip ci]
1 parent 526da7b commit d3fc534

File tree

2 files changed

+82
-80
lines changed

2 files changed

+82
-80
lines changed

src/sentry/deletions/README.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
The deletion subsystem manages asynchronous scheduled bulk deletes as well as cascading deletes
2+
into relations. When adding new models to the application, you should consider how those records will
3+
be deleted when a project or organization are deleted.
4+
5+
The deletion subsystem uses records in PostgreSQL to track deletions and their status. This also
6+
allows deletions to be retried when a deploy interrupts a deletion task, or a deletion job fails
7+
because of a new relation or database failure.
8+
9+
## Taskbroker Tasks
10+
11+
Every 15 minutes `sentry.tasks.deletion.run_scheduled_deletions()` runs. This task queries for jobs
12+
that were scheduled to be run in the past that are not already in progress. Tasks are spawned for
13+
each deletion that needs to be processed.
14+
15+
If a task fails, the daily run of `sentry.tasks.deletion.reattempt_deletions()` will
16+
clear the `in_progress` flag of old jobs so that they are picked up by the next scheduled run.
17+
18+
## Scheduling Deletions
19+
20+
The entrypoint into deletions for the majority of application code is via the `ScheduledDeletion`
21+
model. This model lets you create deletion jobs that are run in the future.
22+
23+
```python
24+
from sentry.deletions.models.scheduleddeletion import ScheduledDeletion
25+
26+
ScheduledDeletion.schedule(organization, days=1, hours=2)
27+
```
28+
29+
The above would schedule an organization to be deleted in 1 day and 2 hours.
30+
31+
## Deletion Tasks
32+
33+
The deletion system provides two base classes to cover common scenarios:
34+
35+
- `ModelDeletionTask` fetches records and deletes each instance individually.
36+
- This strategy is good for models that rely on Django signals or have child relations.
37+
- This strategy is also the default used when a deletion task isn't specified for a model.
38+
- `BulkModelDeletionTask` deletes records in bulk using a single query.
39+
- This strategy is well suited to removing records that don't have any relations.
40+
41+
If your model has child relations that need to be cleaned up you should implement a custom
42+
deletion task. Doing so requires a few steps:
43+
44+
1. Add your deletion task subclass to `sentry.deletions.defaults`
45+
2. Add your deletion task to the default manager mapping in `sentry.deletions.__init__`.
46+
47+
## Undoing Deletions
48+
49+
If you have scheduled a record for deletion and want to be able to cancel that deletion, your
50+
deletion task needs to implement the `should_proceed` hook.
51+
52+
```python
53+
def should_proceed(self, instance: ModelT) -> bool:
54+
return instance.status in {
55+
ObjectStatus.PENDING_DELETION,
56+
ObjectStatus.DELETION_IN_PROGRESS
57+
}
58+
```
59+
60+
The above would only proceed with the deletion if the record's status was correct. When a deletion
61+
is cancelled by this hook, the `ScheduledDeletion` row will be removed.
62+
63+
## Using Deletions Manager Directly
64+
65+
For example, let's say you want to delete an organization:
66+
67+
```python
68+
from sentry import deletions
69+
task = deletions.get(model=Organization, query={})
70+
work = True
71+
while work:
72+
work = task.chunk()
73+
```
74+
75+
The system has a default task implementation to handle Organization which will efficiently cascade
76+
deletes. This behavior varies based on the input object, as the task can override the behavior for
77+
its children.
78+
79+
For example, when you delete a Group, it will cascade in a more traditional manner. It will batch
80+
each child (such as Event). However, when you delete a project, it won't actually cascade to the
81+
registered Group task. It will instead take a more efficient approach of batch deleting its indirect
82+
descendants, such as Event, so it can more efficiently bulk delete rows.

src/sentry/deletions/__init__.py

Lines changed: 0 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,3 @@
1-
"""
2-
The deletions subsystem manages asynchronous scheduled bulk deletes as well as cascading deletes
3-
into relations. When adding new models to the application you should consider how those records will
4-
be deleted when a project or organization are deleted.
5-
6-
The deletion subsystem uses records in postgres to track deletions and their status. This also
7-
allows deletions to be retried when a deploy interrupts a deletion task, or a deletion job fails
8-
because of a new relation or database failure.
9-
10-
Celery Tasks
11-
------------
12-
13-
Every 15 minutes `sentry.tasks.deletion.run_scheduled_deletions()` runs. This task queries for jobs
14-
that were scheduled to be run in the past that are not already in progress. Tasks are spawned for
15-
each deletion that needs to be processed.
16-
17-
If tasks fail, the daily run of `sentry.tasks.deletion.reattempt_deletions()` will
18-
clear the `in_progress` flag of old jobs so that they are picked up by the next scheduled run.
19-
20-
Scheduling Deletions
21-
--------------------
22-
23-
The entrypoint into deletions for the majority of application code is via the ``ScheduledDeletion``
24-
model. This model lets you create deletion jobs that are run in the future.
25-
26-
>>> from sentry.models.scheduledeltion import ScheduledDeletion
27-
>>> ScheduledDeletion.schedule(organization, days=1, hours=2)
28-
29-
The above would schedule an organization to be deleted in 1 day and 2 hours.
30-
31-
Deletion Tasks
32-
--------------
33-
34-
The deletions system provides two base classes to cover common scenarios:
35-
36-
- ``ModelDeletionTask`` fetches records and deletes each instance individually. This strategy is
37-
good for models that rely on django signals or have child relations. This strategy is also the
38-
default used when a deletion task isn't specified for a model.
39-
- ``BulkModelDeletionTask`` Deletes records in bulk using a single query. This strategy is well
40-
suited to removing records that don't have any relations.
41-
42-
If your model has child relations that need to be cleaned up you should implement a custom
43-
deletion task. Doing so requires a few steps:
44-
45-
1. Add your deletion task subclass to `sentry.deletions.defaults`
46-
2. Add your deletion task to the default manager mapping in `sentry.deletions.__init__`.
47-
48-
Undoing Deletions
49-
-----------------
50-
51-
If you have scheduled a record for deletion and want to be able to cancel that deletion, your
52-
deletion task needs to implement the `should_proceed` hook.
53-
54-
>>> def should_proceed(self, instance):
55-
>>> return instance.status in {ObjectStatus.PENDING_DELETION, ObjectStatus.DELETION_IN_PROGRESS}
56-
57-
The above would only proceed with the deletion if the record's status was correct. When a deletion
58-
is cancelled by this hook, the `ScheduledDeletion` row will be removed.
59-
60-
Using Deletions Manager Directly
61-
--------------------------------
62-
63-
For example, let's say you want to delete an organization:
64-
65-
>>> from sentry import deletions
66-
>>> task = deletions.get(model=Organization, query={})
67-
>>> work = True
68-
>>> while work:
69-
>>> work = task.chunk()
70-
71-
The system has a default task implementation to handle Organization which will efficiently cascade
72-
deletes. This behavior varies based on the input object, as the task can override the behavior for
73-
it's children.
74-
75-
For example, when you delete a Group, it will cascade in a more traditional manner. It will batch
76-
each child (such as Event). However, when you delete a project, it won't actually cascade to the
77-
registered Group task. It will instead take a more efficient approach of batch deleting its indirect
78-
descendants, such as Event, so it can more efficiently bulk delete rows.
79-
"""
80-
811
from __future__ import annotations
822

833
import functools

0 commit comments

Comments
 (0)