Repository: getsentry/sentry

Issue:
Cleanup task shows progress bar on stderr
This makes silencing the cleanup task for cron consumption dangerous, because I would have to ignore real errors too.
For sentry 7 I posted a similar issue in the past, #1798 so you might have a Déjà vu
I didn't reopen that other issue, because this time it is probably caused by something else.



Discussion:
@do3cc Do you mean when calling `sentry cleanup` or something else?

The referenced code is in cleanup_unused_files in the cleanup task

@mattrobenolt exactly, sentry cleanup

I am analysing and will provide a PR
Intermediate result:
https://github.com/niltonvolpato/python-progressbar/issues/51


Resolving patch:
diff --git a/src/sentry/runner/commands/cleanup.py b/src/sentry/runner/commands/cleanup.py
--- a/src/sentry/runner/commands/cleanup.py
+++ b/src/sentry/runner/commands/cleanup.py
@@ -36,8 +36,9 @@ def get_project(value):
 @click.option('--days', default=30, type=int, show_default=True, help='Numbers of days to truncate on.')
 @click.option('--project', help='Limit truncation to only entries from project.')
 @click.option('--concurrency', type=int, default=1, show_default=True, help='The number of concurrent workers to run.')
+@click.option('--quiet/--verbose', default=False)
 @configuration
-def cleanup(days, project, concurrency):
+def cleanup(days, project, concurrency, quiet):
     """Delete a portion of trailing data based on creation date.
 
     All data that is older than `--days` will be deleted.  The default for
@@ -66,7 +67,8 @@ def cleanup(days, project, concurrency):
         (Group, 'last_seen'),
     )
 
-    click.echo("Removing expired values for LostPasswordHash")
+    if not quiet:
+        click.echo("Removing expired values for LostPasswordHash")
     LostPasswordHash.objects.filter(
         date_added__lte=timezone.now() - timedelta(hours=48)
     ).delete()
@@ -79,7 +81,8 @@ def cleanup(days, project, concurrency):
             click.echo('Error: Project not found', err=True)
             raise click.Abort()
     else:
-        click.echo("Removing old NodeStore values")
+        if not quiet:
+            click.echo("Removing old NodeStore values")
         cutoff = timezone.now() - timedelta(days=days)
         try:
             nodestore.cleanup(cutoff)
@@ -87,11 +90,12 @@ def cleanup(days, project, concurrency):
             click.echo("NodeStore backend does not support cleanup operation", err=True)
 
     for model, dtfield in BULK_DELETES:
-        click.echo("Removing {model} for days={days} project={project}".format(
-            model=model.__name__,
-            days=days,
-            project=project or '*',
-        ))
+        if not quiet:
+            click.echo("Removing {model} for days={days} project={project}".format(
+                model=model.__name__,
+                days=days,
+                project=project or '*',
+            ))
         BulkDeleteQuery(
             model=model,
             dtfield=dtfield,
@@ -101,7 +105,8 @@ def cleanup(days, project, concurrency):
 
     # EventMapping is fairly expensive and is special cased as it's likely you
     # won't need a reference to an event for nearly as long
-    click.echo("Removing expired values for EventMapping")
+    if not quiet:
+        click.echo("Removing expired values for EventMapping")
     BulkDeleteQuery(
         model=EventMapping,
         dtfield='date_added',
@@ -111,15 +116,17 @@ def cleanup(days, project, concurrency):
 
     # Clean up FileBLob instances which are no longer used and aren't super
     # recent (as there could be a race between blob creation and reference)
-    click.echo("Cleaning up unused FileBlob references")
-    cleanup_unused_files()
+    if not quiet:
+        click.echo("Cleaning up unused FileBlob references")
+    cleanup_unused_files(quiet)
 
     for model, dtfield in GENERIC_DELETES:
-        click.echo("Removing {model} for days={days} project={project}".format(
-            model=model.__name__,
-            days=days,
-            project=project or '*',
-        ))
+        if not quiet:
+            click.echo("Removing {model} for days={days} project={project}".format(
+                model=model.__name__,
+                days=days,
+                project=project or '*',
+            ))
         BulkDeleteQuery(
             model=model,
             dtfield=dtfield,
@@ -128,7 +135,7 @@ def cleanup(days, project, concurrency):
         ).execute_generic()
 
 
-def cleanup_unused_files():
+def cleanup_unused_files(quiet=False):
     """
     Remove FileBlob's (and thus the actual files) if they are no longer
     referenced by any File.
@@ -138,14 +145,17 @@ def cleanup_unused_files():
     referenced.
     """
     from sentry.models import File, FileBlob, FileBlobIndex
-    from sentry.utils.query import RangeQuerySetWrapperWithProgressBar
+    if quiet:
+        from sentry.utils.query import RangeQuerySetWrapper
+    else:
+        from sentry.utils.query import RangeQuerySetWrapperWithProgressBar as RangeQuerySetWrapper
 
     cutoff = timezone.now() - timedelta(days=1)
     queryset = FileBlob.objects.filter(
         timestamp__lte=cutoff,
     )
 
-    for blob in RangeQuerySetWrapperWithProgressBar(queryset):
+    for blob in RangeQuerySetWrapper(queryset):
         if FileBlobIndex.objects.filter(blob=blob).exists():
             continue
         if File.objects.filter(blob=blob).exists():


Test patch: