Compare commits

..

17 Commits

Author SHA1 Message Date
3d48e86c5b Merge pull request 'fix' (#17) from master into dev
Reviewed-on: #17
2025-06-16 16:33:42 +03:00
Egor Matveev
3dd862b287 fix
All checks were successful
Deploy Prod / Push (pull_request) Successful in 9s
Deploy Prod / Deploy prod (pull_request) Successful in 9s
Deploy Dev / Build (pull_request) Successful in 25s
Deploy Dev / Push (pull_request) Successful in 15s
Deploy Dev / Deploy dev (pull_request) Successful in 11s
Deploy Prod / Build (pull_request) Successful in 5s
2025-06-16 16:33:23 +03:00
9207037ebe Merge pull request 'fix' (#16) from master into dev
Reviewed-on: #16
2025-06-16 16:30:08 +03:00
Egor Matveev
786f44a29c fix
All checks were successful
Deploy Dev / Push (pull_request) Successful in 8s
Deploy Dev / Build (pull_request) Successful in 5s
Deploy Dev / Deploy dev (pull_request) Successful in 11s
2025-06-16 16:29:48 +03:00
aa309890cd Merge pull request 'fix' (#15) from master into dev
Reviewed-on: #15
2025-06-16 16:27:55 +03:00
Egor Matveev
64ef3ff776 fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 22s
Deploy Dev / Push (pull_request) Successful in 13s
Deploy Dev / Deploy dev (pull_request) Successful in 14s
2025-06-16 16:27:07 +03:00
73569e0839 Merge pull request 'master' (#14) from master into dev
Reviewed-on: #14
2024-11-24 23:19:26 +03:00
fdb4cc98e8 fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 6s
Deploy Dev / Push (pull_request) Successful in 8s
Deploy Dev / Deploy dev (pull_request) Successful in 7s
2024-11-24 23:10:05 +03:00
903a77102c fix
All checks were successful
Deploy Prod / Build (pull_request) Successful in 5s
Deploy Prod / Push (pull_request) Successful in 7s
Deploy Prod / Deploy prod (pull_request) Successful in 7s
2024-11-24 21:08:19 +03:00
71b1f1d4a3 Merge pull request 'fix' (#11) from master into dev
Reviewed-on: #11
2024-11-24 21:05:25 +03:00
03be5ff8e7 fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 6s
Deploy Dev / Push (pull_request) Successful in 8s
Deploy Dev / Deploy dev (pull_request) Successful in 8s
Deploy Prod / Build (pull_request) Successful in 5s
Deploy Prod / Push (pull_request) Successful in 7s
Deploy Prod / Deploy prod (pull_request) Successful in 7s
2024-11-24 21:04:48 +03:00
0583fae9cc Merge pull request 'fix' (#9) from master into dev
Reviewed-on: #9
2024-11-24 18:14:54 +03:00
d8607b8efc fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 7s
Deploy Dev / Push (pull_request) Successful in 9s
Deploy Dev / Deploy dev (pull_request) Successful in 8s
Deploy Prod / Build (pull_request) Successful in 5s
Deploy Prod / Push (pull_request) Successful in 7s
Deploy Prod / Deploy prod (pull_request) Successful in 7s
2024-11-24 18:14:08 +03:00
342264d7c7 Merge pull request 'fix' (#8) from master into dev
Reviewed-on: #8
2024-11-24 13:05:00 +03:00
8b871775e6 fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 6s
Deploy Dev / Push (pull_request) Successful in 7s
Deploy Dev / Deploy dev (pull_request) Successful in 8s
2024-11-24 13:04:18 +03:00
81c70b61d4 Merge pull request 'fix' (#6) from master into dev
Reviewed-on: #6
2024-11-24 12:12:48 +03:00
90de13452f fix
All checks were successful
Deploy Dev / Build (pull_request) Successful in 6s
Deploy Dev / Push (pull_request) Successful in 8s
Deploy Prod / Build (pull_request) Successful in 4s
Deploy Dev / Deploy dev (pull_request) Successful in 8s
Deploy Prod / Push (pull_request) Successful in 8s
Deploy Prod / Deploy prod (pull_request) Successful in 8s
2024-11-24 12:12:28 +03:00
13 changed files with 62 additions and 8 deletions

View File

@@ -6,6 +6,7 @@ services:
image: mathwave/sprint-repo:configurator image: mathwave/sprint-repo:configurator
networks: networks:
- configurator-development - configurator-development
- monitoring
environment: environment:
MONGO_HOST: "mongo.develop.sprinthub.ru" MONGO_HOST: "mongo.develop.sprinthub.ru"
MONGO_PASSWORD: $MONGO_PASSWORD_DEV MONGO_PASSWORD: $MONGO_PASSWORD_DEV
@@ -20,3 +21,5 @@ services:
networks: networks:
configurator-development: configurator-development:
external: true external: true
monitoring:
external: true

View File

@@ -6,6 +6,7 @@ services:
image: mathwave/sprint-repo:configurator image: mathwave/sprint-repo:configurator
networks: networks:
- configurator - configurator
- monitoring
environment: environment:
MONGO_HOST: "mongo.sprinthub.ru" MONGO_HOST: "mongo.sprinthub.ru"
MONGO_PASSWORD: $MONGO_PASSWORD_PROD MONGO_PASSWORD: $MONGO_PASSWORD_PROD
@@ -20,3 +21,5 @@ services:
networks: networks:
configurator: configurator:
external: true external: true
monitoring:
external: true

View File

View File

@@ -0,0 +1,14 @@
import datetime
import zoneinfo
from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware
from app.utils.monitoring import monitoring
class MetricsMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
start = datetime.datetime.now(zoneinfo.ZoneInfo("Europe/Moscow"))
response: Response = await call_next(request)
end = datetime.datetime.now(zoneinfo.ZoneInfo("Europe/Moscow"))
monitoring.send_metric(start, end, request.url.path, response.status_code, request.method)
return response

View File

@@ -13,7 +13,7 @@ class RequestPostBody(pydantic.BaseModel):
class RequestPutBody(pydantic.BaseModel): class RequestPutBody(pydantic.BaseModel):
id: str id: str
value: dict value: dict|list
class RequestDeleteBody(pydantic.BaseModel): class RequestDeleteBody(pydantic.BaseModel):
@@ -23,7 +23,7 @@ class RequestDeleteBody(pydantic.BaseModel):
class Config(pydantic.BaseModel): class Config(pydantic.BaseModel):
id: str id: str
name: str name: str
value: dict value: dict|list
router = fastapi.APIRouter() router = fastapi.APIRouter()

View File

@@ -1,3 +1,4 @@
import bson
import fastapi import fastapi
import pydantic import pydantic
@@ -37,14 +38,14 @@ async def post(body: RequestPostBody):
@router.put('/api/v1/experiments', status_code=fastapi.status.HTTP_202_ACCEPTED, responses={404: {'description': 'Not found'}}) @router.put('/api/v1/experiments', status_code=fastapi.status.HTTP_202_ACCEPTED, responses={404: {'description': 'Not found'}})
async def put(body: RequestPutBody): async def put(body: RequestPutBody):
changed = await experiments.update(id=body.id, enabled=body.enabled, condition=body.condition) changed = await experiments.update(id=bson.ObjectId(body.id), enabled=body.enabled, condition=body.condition)
if not changed: if not changed:
raise fastapi.HTTPException(404) raise fastapi.HTTPException(404)
@router.delete('/api/v1/experiments', status_code=fastapi.status.HTTP_202_ACCEPTED, responses={404: {'description': 'Not found'}}) @router.delete('/api/v1/experiments', status_code=fastapi.status.HTTP_202_ACCEPTED, responses={404: {'description': 'Not found'}})
async def delete(body: RequestDeleteBody): async def delete(body: RequestDeleteBody):
changed = await experiments.delete(id=body.id) changed = await experiments.delete(id=bson.ObjectId(body.id))
if not changed: if not changed:
raise fastapi.HTTPException(404) raise fastapi.HTTPException(404)

View File

@@ -20,7 +20,7 @@ class PlatformStaff(pydantic.BaseModel):
class ResponseBody(pydantic.BaseModel): class ResponseBody(pydantic.BaseModel):
configs: dict[str, dict] configs: dict[str, dict|list]
experiments: dict[str, ExperimentData] experiments: dict[str, ExperimentData]
platform_staff: PlatformStaff platform_staff: PlatformStaff
@@ -28,7 +28,7 @@ class ResponseBody(pydantic.BaseModel):
router = fastapi.APIRouter() router = fastapi.APIRouter()
@router.post('/api/v1/fetch') @router.get('/api/v1/fetch')
async def execute(stage: str, project: str): async def execute(stage: str, project: str):
confs, exps, staffs = await asyncio.gather( confs, exps, staffs = await asyncio.gather(
configs.get(project=project, stage=stage), configs.get(project=project, stage=stage),

View File

@@ -23,6 +23,7 @@ def create_indexes():
database.get_collection('experiments').create_index([ database.get_collection('experiments').create_index([
('stage', 1), ('stage', 1),
('project', 1), ('project', 1),
('name', 1),
], unique=True) ], unique=True)
database.get_collection('staff').create_index([ database.get_collection('staff').create_index([
('platform_id', 1), ('platform_id', 1),

View File

@@ -12,7 +12,7 @@ class Config(pydantic.BaseModel):
name: str name: str
project: str project: str
stage: str stage: str
value: dict value: dict|list
_id: bson.ObjectId|None = None _id: bson.ObjectId|None = None
@@ -21,7 +21,7 @@ async def create(config: Config) -> str:
return result.inserted_id return result.inserted_id
async def update_data(id: bson.ObjectId, value: dict) -> bool: async def update_data(id: bson.ObjectId, value: dict|list) -> bool:
result = await collection.update_one({'_id': id}, {'$set': {'value': value}}) result = await collection.update_one({'_id': id}, {'$set': {'value': value}})
return result.modified_count != 0 return result.modified_count != 0
@@ -35,4 +35,5 @@ async def get(project: str, stage: str) -> list[Config]:
result = [] result = []
async for item in collection.find({'stage': stage, 'project': project}): async for item in collection.find({'stage': stage, 'project': project}):
result.append(Config.model_validate(item)) result.append(Config.model_validate(item))
result[-1]._id = item['_id']
return result return result

View File

@@ -36,4 +36,5 @@ async def get(project: str, stage: str) -> list[Experiment]:
result = [] result = []
async for item in collection.find({'stage': stage, 'project': project}): async for item in collection.find({'stage': stage, 'project': project}):
result.append(Experiment.model_validate(item)) result.append(Experiment.model_validate(item))
result[-1]._id = item['_id']
return result return result

24
app/utils/monitoring.py Normal file
View File

@@ -0,0 +1,24 @@
from concurrent.futures import ThreadPoolExecutor
import datetime
import requests
class Monitroing:
def __init__(self):
self.executor = ThreadPoolExecutor(max_workers=1)
def send_metric(self, start: datetime.datetime, end: datetime.datetime, endpoint: str, status_code: int, method: str):
def send():
requests.post(f'http://monitoring:1237/api/v1/metrics/endpoint', json={
'timestamp': start.strftime("%Y-%m-%dT%H:%M:%S") + "Z",
'service': 'configurator',
'endpoint': endpoint,
'status_code': status_code,
'response_time': (end - start).microseconds // 1000,
'method': method,
})
self.executor.submit(send)
monitoring = Monitroing()

View File

@@ -1,6 +1,7 @@
import fastapi import fastapi
import uvicorn import uvicorn
from app.middlewares.metrics import MetricsMiddleware
from app.routers import experiments from app.routers import experiments
from app.routers import configs from app.routers import configs
from app.routers import staff from app.routers import staff
@@ -10,6 +11,7 @@ from app.storage import mongo
app = fastapi.FastAPI() app = fastapi.FastAPI()
app.add_middleware(MetricsMiddleware)
app.include_router(experiments.router) app.include_router(experiments.router)
app.include_router(configs.router) app.include_router(configs.router)

View File

@@ -1,6 +1,8 @@
annotated-types==0.7.0 annotated-types==0.7.0
anyio==4.6.2.post1 anyio==4.6.2.post1
APScheduler==3.10.4 APScheduler==3.10.4
certifi==2025.6.15
charset-normalizer==3.4.2
click==8.1.7 click==8.1.7
dnspython==2.7.0 dnspython==2.7.0
fastapi==0.115.4 fastapi==0.115.4
@@ -12,9 +14,11 @@ pydantic_core==2.23.4
pymongo==4.9.2 pymongo==4.9.2
pytz==2024.2 pytz==2024.2
redis==5.2.0 redis==5.2.0
requests==2.32.4
six==1.16.0 six==1.16.0
sniffio==1.3.1 sniffio==1.3.1
starlette==0.41.2 starlette==0.41.2
typing_extensions==4.12.2 typing_extensions==4.12.2
tzlocal==5.2 tzlocal==5.2
urllib3==2.4.0
uvicorn==0.32.0 uvicorn==0.32.0