Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support redis migrations #8898

Merged
merged 33 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
7a32e8b
Draft: add custom 'migrateredis' management command
Marishka17 Jan 3, 2025
78338c7
Merge branch 'develop' into mk/redis-migrations
Marishka17 Jan 10, 2025
10e3a1d
[draft] Add MigrationLoader
Marishka17 Jan 10, 2025
fae0974
Move logic to a separate app
Marishka17 Jan 15, 2025
88ef5a0
Merge branch 'develop' into mk/redis-migrations
Marishka17 Jan 15, 2025
dc1f3bb
Fix linter issues
Marishka17 Jan 15, 2025
233d0a9
Add test migration
Marishka17 Jan 16, 2025
a9ae8fd
Merge branch 'develop' into mk/redis-migrations
Marishka17 Jan 16, 2025
fac9f58
Run migrateredis before syncperiodicjobs
Marishka17 Jan 16, 2025
603fe90
linters
Marishka17 Jan 16, 2025
0b49bbe
Notify if there are no migrations
Marishka17 Jan 16, 2025
170e0f3
Support Redis migrations from enterprise apps
Marishka17 Jan 16, 2025
2bb68c9
Run CI
Marishka17 Jan 16, 2025
bd756e1
Fix minor stupid comments
Marishka17 Jan 16, 2025
580f9a8
Simplify the code
Marishka17 Jan 17, 2025
bbb12b6
Move periodic job commands to redis_handler
Marishka17 Jan 17, 2025
0bea986
Update development guide
Marishka17 Jan 17, 2025
0f75340
Store applied migartions in Redis
Marishka17 Jan 17, 2025
c46a7b4
Add check option
Marishka17 Jan 17, 2025
1131db9
Merge branch 'develop' into mk/redis-migrations
Marishka17 Jan 17, 2025
96f7a7a
allow using shared connection
Marishka17 Jan 17, 2025
1834099
Merge remote-tracking branch 'origin/mk/redis-migrations' into mk/red…
Marishka17 Jan 17, 2025
634f460
changelog
Marishka17 Jan 17, 2025
5582bd9
Update cvat/apps/redis_handler/migration_loader.py
Marishka17 Jan 17, 2025
36ae237
Resolve conflicts
Marishka17 Jan 27, 2025
ba1ef79
add empty line
Marishka17 Jan 27, 2025
942a78c
fix black issue
Marishka17 Jan 27, 2025
32243a7
[tests] Do not reset cvat migrations from redis
Marishka17 Jan 27, 2025
7478890
Apply comments
Marishka17 Jan 30, 2025
f08bd9b
Merge branch 'develop' into mk/redis-migrations
Marishka17 Jan 30, 2025
4d5f70c
Merge branch 'develop' into mk/redis-migrations
Marishka17 Jan 30, 2025
98d0037
Merge branch 'develop' into mk/redis-migrations
Marishka17 Jan 31, 2025
af4b01a
Pass connection to migration class && do not use key prefix in the set
Marishka17 Feb 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backend_entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ cmd_init() {

wait-for-it "${CVAT_REDIS_INMEM_HOST}:${CVAT_REDIS_INMEM_PORT:-6379}" -t 0
~/manage.py syncperiodicjobs
~/manage.py migrateredis
}

cmd_run() {
Expand Down
50 changes: 50 additions & 0 deletions cvat/apps/engine/management/commands/migrateredis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Copyright (C) 2025 CVAT.ai Corporation
#
# SPDX-License-Identifier: MIT

import importlib.util as importlib_util
import sys
from pathlib import Path
from typing import cast

from django.conf import settings
from django.core.management.base import BaseCommand

from cvat.apps.engine.models import RedisMigration
from cvat.apps.engine.redis_migrations import BaseMigration


def get_migration_class(module_name: str, file_path: Path) -> BaseMigration:
spec = importlib_util.spec_from_file_location(module_name, file_path)
module = importlib_util.module_from_spec(spec)
spec.loader.exec_module(module)
MigrationClass = getattr(module, "Migration", None)
if not MigrationClass or not issubclass(MigrationClass, BaseMigration):
raise Exception(f"Invalid migration: {file_path}")

return MigrationClass


class Command(BaseCommand):
help = "Applies Redis migrations and records them in the database"

def handle(self, *args, **options) -> None:
migrations_dir = Path(settings.REDIS_MIGRATIONS_ROOT)
Marishka17 marked this conversation as resolved.
Show resolved Hide resolved
applied_migrations = RedisMigration.objects.all().values_list("name")

for migration_file in sorted(migrations_dir.glob("[0-9]*.py")):
migration_name = migration_file.stem
if migration_name in applied_migrations:
continue

migration = get_migration_class(module_name=migration_name, file_path=migration_file)
try:
migration.run()
Marishka17 marked this conversation as resolved.
Show resolved Hide resolved
RedisMigration.objects.create(name=migration_name)
self.stdout.write(
self.style.SUCCESS(f"Successfully applied migration: {migration_name}")
)
except Exception as e:
self.stderr.write(self.style.ERROR(f"Failed to apply migration: {migration_name}"))
self.stderr.write(str(e))
Marishka17 marked this conversation as resolved.
Show resolved Hide resolved
break
Marishka17 marked this conversation as resolved.
Show resolved Hide resolved
26 changes: 26 additions & 0 deletions cvat/apps/engine/migrations/0087_redismigration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 4.2.16 on 2025-01-03 17:08

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("engine", "0086_profile_has_analytics_access"),
]

operations = [
migrations.CreateModel(
name="RedisMigration",
fields=[
(
"id",
models.AutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("name", models.CharField(max_length=256)),
("applied_date", models.DateTimeField(auto_now_add=True)),
],
),
]
6 changes: 6 additions & 0 deletions cvat/apps/engine/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1345,3 +1345,9 @@ class RequestSubresource(TextChoices):
ANNOTATIONS = "annotations"
DATASET = "dataset"
BACKUP = "backup"


class RedisMigration(models.Model):
# todo: redis_inmem/redis_ondisk
SpecLad marked this conversation as resolved.
Show resolved Hide resolved
name = models.CharField(max_length=256)
applied_date = models.DateTimeField(auto_now_add=True)
8 changes: 8 additions & 0 deletions cvat/apps/engine/redis_migrations/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from abc import ABCMeta, abstractmethod


class BaseMigration(metaclass=ABCMeta):

@staticmethod
@abstractmethod
def run() -> None: ...
2 changes: 2 additions & 0 deletions cvat/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,8 @@ class CVAT_QUEUES(Enum):
# Make sure to update other config files when updating these directories
DATA_ROOT = os.path.join(BASE_DIR, 'data')

REDIS_MIGRATIONS_ROOT = os.path.join(BASE_DIR, 'cvat', 'apps', 'engine', 'redis_migrations')

MEDIA_DATA_ROOT = os.path.join(DATA_ROOT, 'data')
os.makedirs(MEDIA_DATA_ROOT, exist_ok=True)

Expand Down
2 changes: 2 additions & 0 deletions dev/format_python_code.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ for paths in \
"cvat/apps/dataset_manager/tests/test_annotation.py" \
"cvat/apps/dataset_manager/tests/utils.py" \
"cvat/apps/events/signals.py" \
"cvat/apps/engine/management/commands/migrateredis.py" \
"cvat/apps/engine/redis_migrations/*.py" \
; do
${BLACK} -- ${paths}
${ISORT} -- ${paths}
Expand Down
Loading