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

G3-271 server health check endpoint #74

Merged
merged 2 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/_format-lint-action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ jobs:
- name: Install Black and Ruff
run: pip install black ruff
- name: Run Ruff Linter
run: ruff src/ tests/
run: ruff check src/ tests/
- name: Run Black Formatter
run: black src/ tests/
457 changes: 232 additions & 225 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "geneweaver-api"
version = "0.7.0a2"
version = "0.7.0a3"
description = "The Geneweaver API"
authors = [
"Alexander Berger <[email protected]>",
Expand All @@ -20,7 +20,7 @@ python = "^3.9"
geneweaver-core = "^0.10.0a2"
fastapi = {extras = ["all"], version = "^0.99.1"}
uvicorn = {extras = ["standard"], version = "^0.24.0"}
geneweaver-db = "0.5.0a2"
geneweaver-db = "0.5.0a8"
psycopg-pool = "^3.1.7"
requests = "^2.31.0"
python-jose = {extras = ["cryptography"], version = "^3.3.0"}
Expand Down
10 changes: 9 additions & 1 deletion src/geneweaver/api/controller/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@
from fastapi import APIRouter, FastAPI, Security
from geneweaver.api import __version__
from geneweaver.api import dependencies as deps
from geneweaver.api.controller import genes, genesets, publications, search, species
from geneweaver.api.controller import (
genes,
genesets,
monitors,
publications,
search,
species,
)
from geneweaver.api.core.config import settings

app = FastAPI(
Expand All @@ -31,5 +38,6 @@
api_router.include_router(publications.router)
api_router.include_router(species.router)
api_router.include_router(search.router)
api_router.include_router(monitors.router)

app.include_router(api_router, prefix=settings.API_PREFIX)
1 change: 1 addition & 0 deletions src/geneweaver/api/controller/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@
GS_PUB_SEARCH_TEXT = (
"Gensets and/or publications search types ('genesets', 'publications') "
)
CHECK_DB_HEALTH = "Check DB health flag"
29 changes: 29 additions & 0 deletions src/geneweaver/api/controller/monitors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""Endpoints related to system health."""

from typing import Optional

from fastapi import APIRouter, Depends, Query
from geneweaver.api import dependencies as deps
from geneweaver.api.services import monitors as monitors_service
from typing_extensions import Annotated

from . import message as api_message

router = APIRouter(prefix="/monitors", tags=["monitors"])


@router.get("/servers/health")
def get_health_check(
cursor: Optional[deps.Cursor] = Depends(deps.cursor),
db_health_check: Annotated[
Optional[bool], Query(description=api_message.CHECK_DB_HEALTH)
] = False,
) -> dict:
"""Return 200 API response if reachable and optionally check db health."""
response = {"status": "UP"}

if db_health_check:
db_health_response = monitors_service.check_db_health(cursor)
response["DB_status"] = db_health_response

return response
20 changes: 20 additions & 0 deletions src/geneweaver/api/services/monitors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"""Service monitors for system health."""

from fastapi.logger import logger
from geneweaver.db.monitor.db_health import health_check as db_health_check
from psycopg import Cursor


def check_db_health(cursor: Cursor) -> dict:
"""Check DB health status.

@param cursor: DB cursor
@return: db health response (dict).
"""
try:
results = db_health_check(cursor)
return results

except Exception as err:
logger.error(err)
raise err
23 changes: 23 additions & 0 deletions tests/controllers/test_monitor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""Tests for system monitor apis."""

from unittest.mock import patch

from tests.data import test_monitors_data

db_health_status = test_monitors_data.get("db_health_status")


@patch("geneweaver.api.services.monitors.check_db_health")
def test_valid_url_req(mock_db_heath_service_call, client):
"""Test valid url request to get system health status."""
response = client.get(
url="/api/monitors/servers/health", params={"db_health_check": False}
)
assert response.status_code == 200

mock_db_heath_service_call.return_value = db_health_status.get("DB_status")
response = client.get(
url="/api/monitors/servers/health", params={"db_health_check": True}
)
assert response.status_code == 200
assert response.json() == db_health_status
8 changes: 8 additions & 0 deletions tests/data/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@

genes_json = importlib.resources.read_text("tests.data", "genes.json")

monitors_json = importlib.resources.read_text("tests.data", "monitors.json")

## laod and returns JSON string as a dictionary

# geneset test data
Expand Down Expand Up @@ -134,6 +136,12 @@
}


## monitors test data
test_monitors_data = {
"db_health_status": json.loads(monitors_json).get("db_health_status"),
}


def get_species_db_resp(species_data: list) -> list:
"""Get species data as returned by DB."""
species = species_data
Expand Down
16 changes: 16 additions & 0 deletions tests/data/monitors.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"db_health_status": {
"status": "UP",
"DB_status": {
"gene_identifier_last_update": {
"gi_date": "2024-06-24T01:54:48.023015+00:00"
},
"gene_count": {
"count": 16
},
"geneset_count": {
"count": 272143
}
}
}
}
28 changes: 28 additions & 0 deletions tests/services/test_monitors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""Tests for system monitor services."""

from unittest.mock import patch

import pytest
from geneweaver.api.services import monitors

from tests.data import test_monitors_data

db_health_status = test_monitors_data.get("db_health_status")


@patch("geneweaver.api.services.monitors.db_health_check")
def test_db_health_check(mock_db_heath):
"""Test call to get db health status."""
mock_db_heath.return_value = db_health_status.get("DB_status")
response = monitors.check_db_health(None)

assert response == db_health_status.get("DB_status")


@patch("geneweaver.api.services.monitors.db_health_check")
def test_db_health_check_error(mock_db_heath):
"""Test error in call to get db health status."""
mock_db_heath.side_effect = Exception("ERROR")

with pytest.raises(expected_exception=Exception):
monitors.check_db_health(None)
Loading