Slide 1

Slide 1 text

Централизованная система управления настройками в ЦИАН 1

Slide 2

Slide 2 text

О себе - Tech Lead в ЦИАН - В разработке 10 лет 2

Slide 3

Slide 3 text

О ЦИАН - 11 млн покупателей и арендаторов в месяц - Ресурс федерального уровня - 10x разработка за 2014-2017 3

Slide 4

Slide 4 text

Централизованная система управления настройками в ЦИАН 4

Slide 5

Slide 5 text

• Не требует перезапуска или перераскатки приложения • Централизованное хранение • Поддержка разных ЯП Зачем? 5

Slide 6

Slide 6 text

Общая схема 6

Slide 7

Slide 7 text

Хранение настроек в Cassandra 7 CREATE TABLE cian.runtime_settings ( runtime text, key text, priority int, filter map, value text, PRIMARY KEY (runtime, key, priority) ) WITH CLUSTERING ORDER BY (key ASC, priority ASC)

Slide 8

Slide 8 text

Хранение настроек в Cassandra 8

Slide 9

Slide 9 text

Старт приложения 9

Slide 10

Slide 10 text

@gen.coroutine def refresh_settings(self, timeout=2, repo=CassandraSettingsRepository()): # type: (float, BaseSettingsRepository) -> None settings = yield repo.get_all_settings(timeout=timeout) settings_dict = defaultdict(list) for setting in settings: settings_dict[setting.key].append(SettingService(setting)) for k, settings in settings_dict.items(): settings_dict[k] = sorted(settings, key=attrgetter('priority'), reverse=True) old_settings = self._settings self._settings = settings_dict yield self.call_watchers(old_settings) Обновление настроек 10

Slide 11

Slide 11 text

• application • server • url-path • environment • email Фильтры. 11

Slide 12

Slide 12 text

Алгоритм фильтрации 12

Slide 13

Slide 13 text

class BasePatternFilterService(BaseFilterService): _context_attr = None def __init__(self, value): # type: (str) -> None super(BasePatternFilterService, self).__init__(value) self._re = re.compile('^%s$' % value, re.IGNORECASE) def check(self, context): # type: (Context) -> bool context_value = getattr(context, self._context_attr) if context_value is None: return False return bool(self._re.search(context_value)) Фильтры 13

Slide 14

Slide 14 text

response = api_request( method='GET', url=urljoin(getattr(runtime_settings, 'REALTY_BILLING_INTEGRATION_API_URL’), '/v1/billing/operations-list/'), params=params, timeout=getattr(runtime_settings, 'BILLING_OPERATIONS_LIST_TIMEOUT', 1.0), ) Использование в коде 14

Slide 15

Slide 15 text

Примеры использования фильтров 15 python | HTTP_TIMEOUT | 0 | null | 0.2 python | HTTP_TIMEOUT | 1 | {“application”: “app1”} | 0.5 python | HTTP_TIMEOUT | 2 | {“application”: “app1”, “url-path”: “api/v1/lvery_slow_method”} | 1 Для технических нужд python | ALLOW_EXP1 | 0 | null | False python | ALLOW_EXP1 | 1 | {“email”: “[email protected]”} | True Для продуктовых нужд

Slide 16

Slide 16 text

• Не требует перезапуска или перераскатки приложения • Централизованное хранение • Поддержка разных ЯП Что в итоге получили? 16 • Быстро и с гарантиями хранения • Возможность навесить свои callback на изменение настроек • Встроенные фильтры • Интеграция с инструментами CI/CD • Работает в микросервисах и монолитах И как бонус...

Slide 17

Slide 17 text

? email: [email protected] facebook: https://www.facebook.com/zaabjuda github: https://github.com/zaabjuda