Skip to content

Commit 3de71f4

Browse files
revert shared pr (#397)
1 parent f5be738 commit 3de71f4

File tree

5 files changed

+93
-46
lines changed

5 files changed

+93
-46
lines changed

django_scaffold/management/commands/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import logging
2+
import time
3+
4+
import redis_lock
5+
from django.conf import settings
6+
from django.core.management.base import BaseCommand, CommandError
7+
from django.core.management.commands.migrate import Command as MigrateCommand
8+
from django.db import connections
9+
from django.db import transaction as django_transaction
10+
from django.db.utils import IntegrityError, ProgrammingError
11+
12+
from services.redis import get_redis_connection
13+
14+
log = logging.getLogger(__name__)
15+
16+
MIGRATION_LOCK_NAME = "djang-migrations-lock"
17+
18+
19+
class MockLock:
20+
def release(self):
21+
pass
22+
23+
24+
class Command(MigrateCommand):
25+
"""
26+
We need to override the migrate command to block on acquiring a lock in Redis.
27+
Otherwise, concurrent worker and api deploys could attempt to run migrations
28+
at the same time which is not safe.
29+
This class is copied from `codecov-api` except it omits logic about faking
30+
certain migrations. When the `legacy_migrations` app is moved to `shared`
31+
and installed in `worker`, which is a prerequisite for core models, we can
32+
delete this.
33+
"""
34+
35+
def _obtain_lock(self):
36+
"""
37+
In certain environments we might be running mutliple servers that will try and run the migrations at the same time. This is
38+
not safe to do. So we have the command obtain a lock to try and run the migration. If it cannot get a lock, it will wait
39+
until it is able to do so before continuing to run. We need to wait for the lock instead of hard exiting on seeing another
40+
server running the migrations because we write code in such a way that the server expects for migrations to be applied before
41+
new code is deployed (but the opposite of new db with old code is fine).
42+
"""
43+
# If we're running in a non-server environment, we don't need to worry about acquiring a lock
44+
if settings.IS_DEV:
45+
return MockLock()
46+
47+
redis_connection = get_redis_connection()
48+
lock = redis_lock.Lock(
49+
redis_connection, MIGRATION_LOCK_NAME, expire=180, auto_renewal=True
50+
)
51+
log.info("Trying to acquire migrations lock...")
52+
acquired = lock.acquire(timeout=180)
53+
54+
if not acquired:
55+
return None
56+
57+
return lock
58+
59+
def handle(self, *args, **options):
60+
log.info("Codecov is starting migrations...")
61+
database = options["database"]
62+
db_connection = connections[database]
63+
options["run_syncdb"] = False
64+
65+
lock = self._obtain_lock()
66+
67+
# Failed to acquire lock due to timeout
68+
if not lock:
69+
log.error("Potential deadlock detected in api migrations.")
70+
raise Exception("Failed to obtain lock for api migration.")
71+
72+
try:
73+
super().handle(*args, **options)
74+
75+
# Autocommit is disabled in worker
76+
django_transaction.commit(database)
77+
except:
78+
log.info("Codecov migrations failed.")
79+
raise
80+
else:
81+
log.info("Codecov migrations succeeded.")
82+
finally:
83+
lock.release()

django_scaffold/settings.py

+3-42
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
ALLOWED_HOSTS = []
1010

1111
DATABASES["default"]["AUTOCOMMIT"] = False
12-
DATABASES["default"]["ENGINE"] = "psqlextra.backend"
1312
if "timeseries" in DATABASES:
1413
DATABASES["timeseries"]["AUTOCOMMIT"] = False
1514

@@ -18,21 +17,10 @@
1817
# Application definition
1918

2019
INSTALLED_APPS = [
21-
"shared.django_apps.legacy_migrations",
22-
"shared.django_apps.codecov_auth",
23-
"shared.django_apps.core",
24-
"shared.django_apps.reports",
20+
"django_scaffold", # must be first to override migrate command
2521
"shared.django_apps.pg_telemetry",
2622
"shared.django_apps.ts_telemetry",
2723
"shared.django_apps.rollouts",
28-
"shared.django_apps.user_measurements",
29-
# Needed after installing user_measurements
30-
"psqlextra",
31-
"django.contrib.admin",
32-
"django.contrib.contenttypes",
33-
"django.contrib.auth",
34-
# Needed for the manage.py commands after installing legacy, codecov_auth, core, reports apps
35-
"django.contrib.messages",
3624
]
3725

3826
TELEMETRY_VANILLA_DB = "default"
@@ -45,36 +33,9 @@
4533

4634
SKIP_RISKY_MIGRATION_STEPS = get_config("migrations", "skip_risky_steps", default=False)
4735

36+
MIDDLEWARE = []
4837

49-
# Needed for makemigrations to work
50-
MIDDLEWARE = [
51-
"django.contrib.auth.middleware.AuthenticationMiddleware",
52-
"django.contrib.messages.middleware.MessageMiddleware",
53-
"django.contrib.sessions.middleware.SessionMiddleware",
54-
"django.middleware.csrf.CsrfViewMiddleware",
55-
]
56-
57-
# Needed for makemigrations to work
58-
TEMPLATES = [
59-
{
60-
"BACKEND": "django.template.backends.django.DjangoTemplates",
61-
"DIRS": [],
62-
"APP_DIRS": True,
63-
"OPTIONS": {
64-
"context_processors": [
65-
"django.template.context_processors.debug",
66-
"django.contrib.auth.context_processors.auth",
67-
"django.template.context_processors.request",
68-
"django.contrib.messages.context_processors.messages",
69-
]
70-
},
71-
}
72-
]
73-
74-
# Allows to use the pgpartition command
75-
PSQLEXTRA_PARTITIONING_MANAGER = (
76-
"shared.django_apps.user_measurements.partitioning.manager"
77-
)
38+
TEMPLATES = []
7839

7940
# Password validation
8041
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators

requirements.in

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
https://github.com/codecov/shared/archive/a5c2ad51b22ea71cf7ce1d4af11ee0cadc7aab62.tar.gz#egg=shared
1+
https://github.com/codecov/shared/archive/2b40636317fa9c242ca0ca130714302b3891fbd4.tar.gz#egg=shared
22
https://github.com/codecov/opentelem-python/archive/refs/tags/v0.0.4a1.tar.gz#egg=codecovopentelem
33
https://github.com/codecov/test-results-parser/archive/5515e960d5d38881036e9127f86320efca649f13.tar.gz#egg=test-results-parser
44
boto3

requirements.txt

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# This file is autogenerated by pip-compile with Python 3.10
2+
# This file is autogenerated by pip-compile with Python 3.9
33
# by the following command:
44
#
55
# pip-compile requirements.in
@@ -363,7 +363,9 @@ requests==2.31.0
363363
respx==0.20.2
364364
# via -r requirements.in
365365
rfc3986[idna2008]==1.4.0
366-
# via httpx
366+
# via
367+
# httpx
368+
# rfc3986
367369
rsa==4.7.2
368370
# via google-auth
369371
s3transfer==0.3.4
@@ -374,7 +376,7 @@ sentry-sdk==1.40.0
374376
# via
375377
# -r requirements.in
376378
# shared
377-
shared @ https://github.com/codecov/shared/archive/a5c2ad51b22ea71cf7ce1d4af11ee0cadc7aab62.tar.gz
379+
shared @ https://github.com/codecov/shared/archive/2b40636317fa9c242ca0ca130714302b3891fbd4.tar.gz
378380
# via -r requirements.in
379381
six==1.15.0
380382
# via
@@ -427,6 +429,7 @@ typing==3.7.4.3
427429
typing-extensions==4.6.3
428430
# via
429431
# asgiref
432+
# kombu
430433
# openai
431434
# opentelemetry-sdk
432435
# pydantic

0 commit comments

Comments
 (0)