mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: better healthcheck
This commit is contained in:
parent
6cd1cf7e9c
commit
46f016f661
8 changed files with 112 additions and 9 deletions
|
|
@ -1,5 +1,6 @@
|
||||||
import os
|
import os
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends
|
||||||
|
from src.routers import health
|
||||||
from src.routers import usergroups
|
from src.routers import usergroups
|
||||||
from src.routers import dev, trail, users, auth, orgs, roles
|
from src.routers import dev, trail, users, auth, orgs, roles
|
||||||
from src.routers.ai import ai
|
from src.routers.ai import ai
|
||||||
|
|
@ -42,6 +43,8 @@ if os.environ.get("CLOUD_INTERNAL_KEY"):
|
||||||
dependencies=[Depends(cloud_internal.check_internal_cloud_key)],
|
dependencies=[Depends(cloud_internal.check_internal_cloud_key)],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
v1_router.include_router(health.router, prefix="/health", tags=["health"])
|
||||||
|
|
||||||
# Dev Routes
|
# Dev Routes
|
||||||
v1_router.include_router(
|
v1_router.include_router(
|
||||||
dev.router,
|
dev.router,
|
||||||
|
|
|
||||||
11
apps/api/src/routers/health.py
Normal file
11
apps/api/src/routers/health.py
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
from fastapi import Depends, APIRouter
|
||||||
|
from sqlmodel import Session
|
||||||
|
from src.services.health.health import check_health
|
||||||
|
from src.core.events.database import get_db_session
|
||||||
|
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
@router.get("")
|
||||||
|
async def health(db_session: Session = Depends(get_db_session)):
|
||||||
|
return await check_health(db_session)
|
||||||
0
apps/api/src/services/health/__init__.py
Normal file
0
apps/api/src/services/health/__init__.py
Normal file
21
apps/api/src/services/health/health.py
Normal file
21
apps/api/src/services/health/health.py
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
from fastapi import HTTPException
|
||||||
|
from sqlmodel import Session, select
|
||||||
|
from src.db.organizations import Organization
|
||||||
|
|
||||||
|
async def check_database_health(db_session: Session) -> bool:
|
||||||
|
statement = select(Organization)
|
||||||
|
result = db_session.exec(statement)
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
async def check_health(db_session: Session) -> bool:
|
||||||
|
# Check database health
|
||||||
|
database_healthy = await check_database_health(db_session)
|
||||||
|
|
||||||
|
if not database_healthy:
|
||||||
|
raise HTTPException(status_code=503, detail="Database is not healthy")
|
||||||
|
|
||||||
|
return True
|
||||||
39
apps/web/app/api/health/route.ts
Normal file
39
apps/web/app/api/health/route.ts
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
export const dynamic = 'force-dynamic' // defaults to auto
|
||||||
|
export const revalidate = 0
|
||||||
|
|
||||||
|
import { NextResponse } from 'next/server';
|
||||||
|
import { checkHealth } from '@services/utils/health';
|
||||||
|
|
||||||
|
export async function GET() {
|
||||||
|
const health = await checkHealth()
|
||||||
|
if (health.success === true) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
status: 'healthy',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
health: health.data,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 200,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return NextResponse.json(
|
||||||
|
{
|
||||||
|
status: 'unhealthy',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
health: null,
|
||||||
|
error: health.HTTPmessage,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
status: 503,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
function HealthPage() {
|
|
||||||
return (
|
|
||||||
<div>OK</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default HealthPage
|
|
||||||
|
|
@ -102,6 +102,11 @@ export default async function middleware(req: NextRequest) {
|
||||||
return NextResponse.rewrite(redirectUrl)
|
return NextResponse.rewrite(redirectUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Health Check
|
||||||
|
if (pathname.startsWith('/health')) {
|
||||||
|
return NextResponse.rewrite(new URL(`/api/health`, req.url))
|
||||||
|
}
|
||||||
|
|
||||||
// Auth Redirects
|
// Auth Redirects
|
||||||
if (pathname == '/redirect_from_auth') {
|
if (pathname == '/redirect_from_auth') {
|
||||||
if (cookie_orgslug) {
|
if (cookie_orgslug) {
|
||||||
|
|
|
||||||
33
apps/web/services/utils/health.ts
Normal file
33
apps/web/services/utils/health.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { getAPIUrl } from '@services/config/config'
|
||||||
|
import {
|
||||||
|
RequestBody,
|
||||||
|
getResponseMetadata,
|
||||||
|
} from '@services/utils/ts/requests'
|
||||||
|
|
||||||
|
export async function checkHealth() {
|
||||||
|
try {
|
||||||
|
const result = await fetch(
|
||||||
|
`${getAPIUrl()}health`,
|
||||||
|
RequestBody('GET', null, null)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!result.ok) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: result.status,
|
||||||
|
HTTPmessage: result.statusText,
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await getResponseMetadata(result)
|
||||||
|
return res
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
status: 503,
|
||||||
|
HTTPmessage: 'Service unavailable',
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue