Projet

Général

Profil

0001-multitenant-show-ETA-on-migrate_schemas-68034.patch

Thomas Noël, 09 décembre 2022 11:26

Télécharger (6,02 ko)

Voir les différences:

Subject: [PATCH] multitenant: show ETA on migrate_schemas (#68034)

 .../management/commands/__init__.py           |  4 +++-
 .../management/commands/migrate_schemas.py    | 24 ++++++++++++++-----
 tests_multitenant/test_create_tenant.py       | 18 ++++++++++++++
 3 files changed, 39 insertions(+), 7 deletions(-)
hobo/multitenant/management/commands/__init__.py
188 188
        if hasattr(settings, 'SHARED_APPS'):
189 189
            self.shared_apps = settings.SHARED_APPS
190 190

  
191
    def _notice(self, output):
191
    def _notice(self, output, flush=False):
192 192
        if int(self.options.get('verbosity', 1)) >= 1:
193 193
            self.stdout.write(self.style.NOTICE(output))
194
            if flush:
195
                self.stdout.flush()
194 196

  
195 197

  
196 198
def disable_global_logging():
hobo/multitenant/management/commands/migrate_schemas.py
21 21
from django.db import connection
22 22
from django.db.migrations.loader import MigrationLoader
23 23
from django.db.migrations.recorder import MigrationRecorder
24
from django.utils.timezone import localtime
24 25
from tenant_schemas.postgresql_backend.base import FakeTenant
25 26
from tenant_schemas.utils import get_public_schema_name, schema_exists
26 27

  
......
59 60
            all_migrations = {
60 61
                (app, migration) for app, migration in loader.disk_migrations if app in app_labels
61 62
            }
62
            for tenant in TenantMiddleware.get_tenants():
63
            tenants = list(TenantMiddleware.get_tenants())
64
            len_tenants = len(tenants)
65
            start_datetime = localtime()
66
            for step, tenant in enumerate(tenants, start=1):
63 67
                connection.set_tenant(tenant, include_public=False)
64 68
                applied_migrations = self.get_applied_migrations(app_labels)
65 69
                if options.get('fake') or options.get('migration_name') or options.get('app_label'):
......
68 72
                    applied_migrations = []
69 73
                if all([x in applied_migrations for x in all_migrations]):
70 74
                    if int(self.options.get('verbosity', 1)) >= 1:
71
                        self._notice("=== Skipping migrations of tenant %s" % tenant.domain_url)
75
                        self._notice(
76
                            "=== Skipping migrations of tenant %s (%s/%s)"
77
                            % (tenant.domain_url, step, len_tenants)
78
                        )
72 79
                    continue
73
                self.run_migrations(tenant, settings.TENANT_APPS)
80
                self.run_migrations(tenant, settings.TENANT_APPS, step, len_tenants)
81
                if int(self.options.get('verbosity', 1)) >= 1:
82
                    eta = start_datetime + len_tenants * (localtime() - start_datetime) / step
83
                    self._notice('=== migrate_schemas ETA: %s' % eta, flush=True)
74 84

  
75 85
    def get_applied_migrations(self, app_labels):
76 86
        applied_migrations = []
......
81 91
        applied_migrations = [x for x in applied_migrations if x[0] in app_labels]
82 92
        return applied_migrations
83 93

  
84
    def run_migrations(self, tenant, included_apps):
94
    def run_migrations(self, tenant, included_apps, step=1, steps=1):
85 95
        if int(self.options.get('verbosity', 1)) >= 1:
86
            self._notice("=== Running migrate for tenant %s" % tenant.domain_url)
96
            self._notice("=== Running migrate for tenant %s (%s/%s)" % (tenant.domain_url, step, steps))
87 97
        connection.set_tenant(tenant, include_public=False)
88 98
        command = MigrateCommand()
89 99
        command.requires_system_checks = False
......
101 111
        command.execute(*self.args, **self.options)
102 112
        connection.set_schema_to_public()
103 113

  
104
    def _notice(self, output):
114
    def _notice(self, output, flush=False):
105 115
        self.stdout.write(self.style.NOTICE(output))
116
        if flush:
117
            self.stdout.flush()
106 118

  
107 119

  
108 120
Command = MigrateSchemasCommand
tests_multitenant/test_create_tenant.py
142 142
    with pytest.raises(CommandError) as exc_info:
143 143
        call_command('create_tenant', '--legacy-hostname', 'host1.com', 'host2.com')
144 144
    assert str(exc_info.value) == 'tenant already exists'
145

  
146

  
147
def test_migrate_schemas_eta(db, capsys):
148
    call_command('create_tenant', 'host1.com')
149
    call_command('create_tenant', 'host2.com')
150
    # all skipped, no ETA is displayed
151
    call_command('migrate_schemas', verbosity=1)
152
    captured = capsys.readouterr()
153
    assert 'Skipping migrations of tenant host1.com (1/2)' in captured.out
154
    assert 'Skipping migrations of tenant host2.com (2/2)' in captured.out
155
    assert 'migrate_schemas ETA: 2' not in captured.out
156
    # force re-migration and re-migrate, ETA is displayed
157
    call_command('migrate_schemas', 'common', '0001_initial', verbosity=1)
158
    call_command('migrate_schemas', verbosity=1)
159
    captured = capsys.readouterr()
160
    assert 'Running migrate for tenant host1.com (1/2)' in captured.out
161
    assert 'Running migrate for tenant host2.com (2/2)' in captured.out
162
    assert 'migrate_schemas ETA: 2' in captured.out
145
-