Fixed compatibility with celery JSON serializer

This commit is contained in:
M1ha-Shvn 2021-03-30 16:09:18 +05:00
parent c1c10ae379
commit 874eae88a0
5 changed files with 62 additions and 9 deletions

View File

@ -51,6 +51,10 @@ env:
- PG=10 DJANGO=3.0 - PG=10 DJANGO=3.0
- PG=11 DJANGO=3.0 - PG=11 DJANGO=3.0
- PG=12 DJANGO=3.0 - PG=12 DJANGO=3.0
- PG=9.6 DJANGO=3.1
- PG=10 DJANGO=3.1
- PG=11 DJANGO=3.1
- PG=12 DJANGO=3.1
before_install: before_install:
# Use default PostgreSQL 11 port # Use default PostgreSQL 11 port

View File

@ -13,7 +13,7 @@ with open('requirements.txt') as f:
setup( setup(
name='django-clickhouse', name='django-clickhouse',
version='1.0.2', version='1.0.3',
packages=['django_clickhouse'], packages=['django_clickhouse'],
package_dir={'': 'src'}, package_dir={'': 'src'},
url='https://github.com/carrotquest/django-clickhouse', url='https://github.com/carrotquest/django-clickhouse',

View File

@ -7,16 +7,19 @@ from infi.clickhouse_orm.utils import import_submodules
from django_clickhouse.clickhouse_models import ClickHouseModel from django_clickhouse.clickhouse_models import ClickHouseModel
from .configuration import config from .configuration import config
from .utils import get_subclasses from .utils import get_subclasses, lazy_class_import
@shared_task(queue=config.CELERY_QUEUE) @shared_task(queue=config.CELERY_QUEUE)
def sync_clickhouse_model(model_cls) -> None: def sync_clickhouse_model(model_cls) -> None:
""" """
Syncs one batch of given ClickHouseModel Syncs one batch of given ClickHouseModel
:param model_cls: ClickHouseModel subclass :param model_cls: ClickHouseModel subclass or python path to it
:return: None :return: None
""" """
model_cls = lazy_class_import(model_cls)
# If sync will not finish it is not fatal to set up sync period here: sync will be executed next time
model_cls.get_storage().set_last_sync_time(model_cls.get_import_key(), datetime.datetime.now()) model_cls.get_storage().set_last_sync_time(model_cls.get_import_key(), datetime.datetime.now())
model_cls.sync_batch_from_storage() model_cls.sync_batch_from_storage()
@ -37,9 +40,8 @@ def clickhouse_auto_sync():
except ImportError: except ImportError:
pass pass
# Start
for cls in get_subclasses(ClickHouseModel, recursive=True): for cls in get_subclasses(ClickHouseModel, recursive=True):
if cls.need_sync(): if cls.need_sync():
# Даже если синхронизация вдруг не выполнится, не страшно, что мы установили период синхронизации # I pass class as a string in order to make it JSON serializable
# Она выполнится следующей таской через интервал. cls_path = "%s.%s" % (cls.__module__, cls.__name__)
sync_clickhouse_model.delay(cls) sync_clickhouse_model.delay(cls_path)

View File

@ -2,7 +2,7 @@ import datetime
from unittest import skipIf from unittest import skipIf
import django import django
from django.test import TransactionTestCase from django.test import TransactionTestCase, TestCase
from django.utils.timezone import now from django.utils.timezone import now
from tests.clickhouse_models import ClickHouseTestModel, ClickHouseSecondTestModel, ClickHouseCollapseTestModel, \ from tests.clickhouse_models import ClickHouseTestModel, ClickHouseSecondTestModel, ClickHouseCollapseTestModel, \
@ -25,6 +25,8 @@ class TestOperations(TransactionTestCase):
fixtures = ['test_model'] fixtures = ['test_model']
django_model = TestModel django_model = TestModel
clickhouse_model = ClickHouseTestModel clickhouse_model = ClickHouseTestModel
databases = ['default', 'secondary']
db_alias = 'default' db_alias = 'default'
multi_db = True multi_db = True

View File

@ -2,15 +2,18 @@ import datetime
import logging import logging
from subprocess import Popen from subprocess import Popen
from time import sleep from time import sleep
from unittest import expectedFailure, skip from unittest import expectedFailure, skip, mock
import os import os
from django.test import TransactionTestCase from django.test import TransactionTestCase
from django.test.testcases import TestCase
from django.utils.timezone import now from django.utils.timezone import now
from random import randint from random import randint
from django_clickhouse.database import connections from django_clickhouse.database import connections
from django_clickhouse.migrations import migrate_app from django_clickhouse.migrations import migrate_app
from django_clickhouse.storages import RedisStorage
from django_clickhouse.tasks import sync_clickhouse_model, clickhouse_auto_sync
from django_clickhouse.utils import int_ranges from django_clickhouse.utils import int_ranges
from tests.clickhouse_models import ClickHouseTestModel, ClickHouseCollapseTestModel, ClickHouseMultiTestModel from tests.clickhouse_models import ClickHouseTestModel, ClickHouseCollapseTestModel, ClickHouseMultiTestModel
from tests.models import TestModel from tests.models import TestModel
@ -207,6 +210,48 @@ class KillTest(TransactionTestCase):
self._check_data() self._check_data()
@mock.patch.object(ClickHouseTestModel, 'sync_batch_from_storage')
class SyncClickHouseModelTest(TestCase):
def test_model_as_class(self, sync_mock):
sync_clickhouse_model(ClickHouseTestModel)
sync_mock.assert_called()
def test_model_as_string(self, sync_mock):
sync_clickhouse_model('tests.clickhouse_models.ClickHouseTestModel')
sync_mock.assert_called()
@mock.patch.object(RedisStorage, 'set_last_sync_time')
def test_last_sync_time_called(self, storage_mock, _):
sync_clickhouse_model(ClickHouseTestModel)
storage_mock.assert_called()
self.assertEqual(2, len(storage_mock.call_args))
self.assertEqual(storage_mock.call_args[0][0], 'ClickHouseTestModel')
self.assertIsInstance(storage_mock.call_args[0][1], datetime.datetime)
@mock.patch.object(sync_clickhouse_model, 'delay')
class ClickHouseAutoSyncTest(TestCase):
@mock.patch('django_clickhouse.tasks.get_subclasses', return_value=[ClickHouseTestModel])
@mock.patch.object(ClickHouseTestModel, 'need_sync', return_value=True)
def test_needs_sync_enabled(self, need_sync_mock, get_subclasses_mock, sync_delay_mock):
clickhouse_auto_sync()
sync_delay_mock.assert_called_with('tests.clickhouse_models.ClickHouseTestModel')
@mock.patch('django_clickhouse.tasks.get_subclasses', return_value=[ClickHouseTestModel])
@mock.patch.object(ClickHouseTestModel, 'need_sync', return_value=False)
def test_does_not_need_sync(self, need_sync_mock, get_subclasses_mock, sync_delay_mock):
clickhouse_auto_sync()
sync_delay_mock.assert_not_called()
@mock.patch('django_clickhouse.tasks.get_subclasses',
return_value=[ClickHouseTestModel, ClickHouseCollapseTestModel])
@mock.patch.object(ClickHouseTestModel, 'need_sync', return_value=True)
@mock.patch.object(ClickHouseCollapseTestModel, 'need_sync', return_value=True)
def test_multiple_models(self, need_sync_1_mock, need_sync_2_mock, get_subclasses_mock, sync_delay_mock):
clickhouse_auto_sync()
self.assertEqual(2, sync_delay_mock.call_count)
# Used to profile sync execution time. Disabled by default # Used to profile sync execution time. Disabled by default
@skip @skip
class ProfileTest(TransactionTestCase): class ProfileTest(TransactionTestCase):