classic-health-checks 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- classic/health_checks/__init__.py +2 -0
- classic/health_checks/health_check.py +46 -0
- classic/health_checks/settings.py +18 -0
- classic_health_checks-0.0.1.dist-info/METADATA +138 -0
- classic_health_checks-0.0.1.dist-info/RECORD +8 -0
- classic_health_checks-0.0.1.dist-info/WHEEL +5 -0
- classic_health_checks-0.0.1.dist-info/licenses/LICENSE +21 -0
- classic_health_checks-0.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import time
|
|
2
|
+
from logging import Logger
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from .settings import HealthCheckSettingsMixin
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class HealthCheck:
|
|
9
|
+
"""
|
|
10
|
+
Задача для выполнения проверки работоспособности путем обновления
|
|
11
|
+
временной метки файла.
|
|
12
|
+
|
|
13
|
+
Этот класс реализует простую проверку жизнеспособности (liveness probe).
|
|
14
|
+
При запуске метода `run` он периодически обновляет указанный файл
|
|
15
|
+
в файловой системе. Внешняя система мониторинга может отслеживать
|
|
16
|
+
время последнего изменения этого файла, чтобы убедиться, что сервис
|
|
17
|
+
активен и не завис.
|
|
18
|
+
|
|
19
|
+
Аргументы:
|
|
20
|
+
logger: Экземпляр стандартного логгера для вывода отладочных сообщений.
|
|
21
|
+
settings: Объект конфигурации с параметрами для проверки.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
logger: Logger,
|
|
27
|
+
settings: HealthCheckSettingsMixin,
|
|
28
|
+
) -> None:
|
|
29
|
+
self.logger = logger
|
|
30
|
+
self.filepath = Path(settings.HEALTHCHECK_FILE_PATH)
|
|
31
|
+
self.interval = settings.HEALTHCHECK_INTERVAL
|
|
32
|
+
self.filepath.parent.mkdir(parents=True, exist_ok=True)
|
|
33
|
+
|
|
34
|
+
def run(self) -> None:
|
|
35
|
+
"""
|
|
36
|
+
Запускает бесконечный цикл проверки работоспособности.
|
|
37
|
+
|
|
38
|
+
Этот метод выполняет бесконечный цикл, в котором:
|
|
39
|
+
1. Обновляет временную метку файла проверки.
|
|
40
|
+
2. Приостанавливает выполнение на заданный интервал.
|
|
41
|
+
3. Логирует отладочное сообщение.
|
|
42
|
+
"""
|
|
43
|
+
while True:
|
|
44
|
+
self.filepath.touch()
|
|
45
|
+
time.sleep(self.interval)
|
|
46
|
+
self.logger.debug('Healthcheck file written')
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from pydantic_settings import BaseSettings
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class HealthCheckSettingsMixin:
|
|
5
|
+
"""
|
|
6
|
+
Настройки конфигурации для задачи проверки работоспособности.
|
|
7
|
+
|
|
8
|
+
Эти настройки могут быть загружены из переменных окружения или .env файла.
|
|
9
|
+
"""
|
|
10
|
+
HEALTHCHECK_FILE_PATH: str
|
|
11
|
+
"""Путь к файлу, используемому для проверки работоспособности."""
|
|
12
|
+
|
|
13
|
+
HEALTHCHECK_INTERVAL: float = 10.0
|
|
14
|
+
"""Интервал в секундах между обновлениями файла проверки."""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class HealthCheckSettings(HealthCheckSettingsMixin, BaseSettings):
|
|
18
|
+
pass
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: classic-health-checks
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Simple health-checks
|
|
5
|
+
Author-email: Sergei Variasov <variasov@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/variasov/classic-health-checks
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Provides-Extra: dev
|
|
14
|
+
Requires-Dist: build~=1.2.2.post1; extra == "dev"
|
|
15
|
+
Requires-Dist: pytest==8.3.4; extra == "dev"
|
|
16
|
+
Requires-Dist: pytest-cov==6.0.0; extra == "dev"
|
|
17
|
+
Requires-Dist: isort==6.0.0; extra == "dev"
|
|
18
|
+
Requires-Dist: yapf==0.43.0; extra == "dev"
|
|
19
|
+
Requires-Dist: flake8==7.1.1; extra == "dev"
|
|
20
|
+
Requires-Dist: Flake8-pyproject==1.2.3; extra == "dev"
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# Classic Health Checks
|
|
24
|
+
|
|
25
|
+
[](https://badge.fury.io/py/classic-health-checks)
|
|
26
|
+
[](https://opensource.org/licenses/MIT)
|
|
27
|
+
|
|
28
|
+
Простая реализация проверки работоспособности сервиса (liveness probe) через обновление временной метки файла.
|
|
29
|
+
|
|
30
|
+
Этот пакет предоставляет задачу, которая может быть запущена в отдельном потоке или гринлете для периодического обновления файла на диске. Внешние системы мониторинга, такие как Kubernetes или systemd, могут отслеживать время последнего изменения этого файла, чтобы убедиться, что сервис активен и не завис.
|
|
31
|
+
|
|
32
|
+
## Установка
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install classic-health-checks
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Использование (Usage)
|
|
39
|
+
|
|
40
|
+
Вот минимальный пример использования `HealthCheck` в отдельном потоке.
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
### Использование с `gevent`
|
|
44
|
+
|
|
45
|
+
Для использования с `gevent` убедитесь, что он установлен:
|
|
46
|
+
```bash
|
|
47
|
+
pip install gevent
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`HealthCheck` легко интегрируется с `gevent`. Инициализируем и запускаем run в гринлете.
|
|
51
|
+
```python
|
|
52
|
+
import gevent
|
|
53
|
+
from gevent.monkey import patch_all
|
|
54
|
+
|
|
55
|
+
patch_all()
|
|
56
|
+
|
|
57
|
+
import logging
|
|
58
|
+
from pydantic_settings import BaseSettings
|
|
59
|
+
from classic.health_checks import HealthCheck, HealthCheckSettingsMixin
|
|
60
|
+
|
|
61
|
+
# Настройте базовый логгер
|
|
62
|
+
logging.basicConfig(
|
|
63
|
+
level=logging.DEBUG,
|
|
64
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
65
|
+
)
|
|
66
|
+
logger = logging.getLogger(__name__)
|
|
67
|
+
|
|
68
|
+
class AppSettings(HealthCheckSettingsMixin, BaseSettings):
|
|
69
|
+
...
|
|
70
|
+
|
|
71
|
+
settings = AppSettings(HEALTHCHECK_FILE_PATH='/tmp/healthcheck')
|
|
72
|
+
|
|
73
|
+
# 1. Создаем экземпляр
|
|
74
|
+
|
|
75
|
+
health_check = HealthCheck(
|
|
76
|
+
logger=logger,
|
|
77
|
+
settings=settings,
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
# 2. Запускаем HealthCheck и другие задачи в своих гринлетах
|
|
81
|
+
|
|
82
|
+
# Псевдо-задачи для примера
|
|
83
|
+
class LongRunningTask:
|
|
84
|
+
def __init__(self, name: str):
|
|
85
|
+
self.name = name
|
|
86
|
+
def run(self):
|
|
87
|
+
logger.info(f"Задача '{self.name}' запущена.")
|
|
88
|
+
while True:
|
|
89
|
+
gevent.sleep(60)
|
|
90
|
+
|
|
91
|
+
task1 = LongRunningTask("Обработчик сообщений")
|
|
92
|
+
task2 = LongRunningTask("Сборщик метрик")
|
|
93
|
+
|
|
94
|
+
all_greenlets = [
|
|
95
|
+
gevent.spawn(health_check.run),
|
|
96
|
+
gevent.spawn(task1.run),
|
|
97
|
+
gevent.spawn(task2.run),
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
logger.info(f"Запущено {len(all_greenlets)} гринлетов, включая HealthCheck.")
|
|
101
|
+
|
|
102
|
+
# 3. Ожидаем завершения всех задач и обрабатываем остановку
|
|
103
|
+
try:
|
|
104
|
+
gevent.joinall(all_greenlets, raise_error=True)
|
|
105
|
+
except (KeyboardInterrupt, SystemExit):
|
|
106
|
+
logger.info("Получен сигнал остановки, завершаем все гринлеты...")
|
|
107
|
+
gevent.killall(all_greenlets)
|
|
108
|
+
logger.info("Приложение остановлено.")
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
> **Подсказка:** "Сигнал остановки" обычно отправляется нажатием `Ctrl+C` в терминале, где запущен скрипт.
|
|
113
|
+
|
|
114
|
+
### Интеграция с Kubernetes
|
|
115
|
+
|
|
116
|
+
Вы можете использовать этот механизм для настройки `livenessProbe` в вашем Helm-чарте:
|
|
117
|
+
|
|
118
|
+
```yaml
|
|
119
|
+
# ... внутри spec.template.spec.containers[]
|
|
120
|
+
# Добавляем переменную окружения, чтобы она была доступна в livenessProbe
|
|
121
|
+
env:
|
|
122
|
+
- name: HEALTHCHECK_FILE_PATH
|
|
123
|
+
value: /tmp/my_app_healthy
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
envsFromSecret:
|
|
127
|
+
secret-envs:
|
|
128
|
+
...
|
|
129
|
+
livenessProbe:
|
|
130
|
+
exec:
|
|
131
|
+
command:
|
|
132
|
+
- /bin/sh
|
|
133
|
+
- -c
|
|
134
|
+
- "[ $(($(date +%s) - $(stat -c %Y $HEALTHCHECK_FILE_PATH))) -le 10 ]"
|
|
135
|
+
periodSeconds: 10
|
|
136
|
+
initialDelaySeconds: 30
|
|
137
|
+
failureThreshold: 3
|
|
138
|
+
```
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
classic/health_checks/__init__.py,sha256=T5w_I9QTG8iAt91UCUhDyGTUY7QZ92nvEEHC9-moGHo,106
|
|
2
|
+
classic/health_checks/health_check.py,sha256=w3zUt7uSL61O-GKsipyLUJnpgxOQF7Q3YwTmOY9nbMg,2137
|
|
3
|
+
classic/health_checks/settings.py,sha256=AINmmz9EUo-w8Q8xT4LMbuvJk_0AO0g4K6wQWFw6Iy8,735
|
|
4
|
+
classic_health_checks-0.0.1.dist-info/licenses/LICENSE,sha256=NJlZYf1BWmSV82IG29S9QdVpNjUsMMIeMwAtJpkkU9w,1071
|
|
5
|
+
classic_health_checks-0.0.1.dist-info/METADATA,sha256=1Jpn-08_ebaOePLl7FgLPsN5r3St-bxXsAvyNYs2OYk,5016
|
|
6
|
+
classic_health_checks-0.0.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
7
|
+
classic_health_checks-0.0.1.dist-info/top_level.txt,sha256=NGd9e95FycaETli7Cs0MwFTtdjK6EYJ3tq_ErbSLNZg,8
|
|
8
|
+
classic_health_checks-0.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Sergei Variasov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
classic
|