feat: trigger health checks automatically when tools are synced

Add non-blocking health check calls to both sync endpoints:
- /api/sync/changes: Triggers health checks after tool upsert from changes feed
- /api/sync/keyword: Triggers health checks after tool upsert from keyword search

Health checks run asynchronously with 'sync' trigger source, ensuring:
- New/updated tools are validated immediately after sync
- Sync operations don't wait for health check completion
- Errors are logged but don't fail the sync

This completes Phase 2 of the health check system implementation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ajax Davis 2025-12-04 16:16:30 +10:00
parent c2b5284da4
commit b51060d9e7
2 changed files with 22 additions and 8 deletions

View file

@ -3,6 +3,7 @@ import { fetchChanges, fetchLatestPackageWithMetadata } from '@tpmjs/npm-client'
import { validateTpmjsField } from '@tpmjs/types/tpmjs';
import { type NextRequest, NextResponse } from 'next/server';
import { env } from '~/env';
import { performHealthCheck } from '~/lib/health-check/health-check-service';
export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';
@ -131,7 +132,7 @@ export async function POST(request: NextRequest) {
// Upsert each tool in the tools array
for (const toolDef of validation.tools) {
await prisma.tool.upsert({
const upsertedTool = await prisma.tool.upsert({
where: {
packageId_exportName: {
packageId: packageRecord.id,
@ -160,6 +161,14 @@ export async function POST(request: NextRequest) {
aiAgent: toolDef.aiAgent ? (toolDef.aiAgent as any) : undefined,
},
});
// Trigger immediate health check (non-blocking)
performHealthCheck(upsertedTool.id, 'sync').catch((err) => {
console.error(
`Health check failed for ${pkg.name}/${toolDef.exportName} (${upsertedTool.id}):`,
err
);
});
}
// Delete orphaned tools (tools removed from package.json)
@ -174,9 +183,7 @@ export async function POST(request: NextRequest) {
id: { in: orphanedTools.map((t) => t.id) },
},
});
console.log(
`Deleted ${orphanedTools.length} orphaned tools from package: ${pkg.name}`
);
console.log(`Deleted ${orphanedTools.length} orphaned tools from package: ${pkg.name}`);
}
processed++;

View file

@ -3,6 +3,7 @@ import { fetchLatestPackageWithMetadata, searchByKeyword } from '@tpmjs/npm-clie
import { validateTpmjsField } from '@tpmjs/types/tpmjs';
import { type NextRequest, NextResponse } from 'next/server';
import { env } from '~/env';
import { performHealthCheck } from '~/lib/health-check/health-check-service';
export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';
@ -145,7 +146,7 @@ export async function POST(request: NextRequest) {
// Upsert each tool in the tools array
for (const toolDef of validation.tools) {
await prisma.tool.upsert({
const upsertedTool = await prisma.tool.upsert({
where: {
packageId_exportName: {
packageId: packageRecord.id,
@ -174,6 +175,14 @@ export async function POST(request: NextRequest) {
aiAgent: toolDef.aiAgent ? (toolDef.aiAgent as any) : undefined,
},
});
// Trigger immediate health check (non-blocking)
performHealthCheck(upsertedTool.id, 'sync').catch((err) => {
console.error(
`Health check failed for ${pkg.name}/${toolDef.exportName} (${upsertedTool.id}):`,
err
);
});
}
// Delete orphaned tools (tools removed from package.json)
@ -188,9 +197,7 @@ export async function POST(request: NextRequest) {
id: { in: orphanedTools.map((t) => t.id) },
},
});
console.log(
`Deleted ${orphanedTools.length} orphaned tools from package: ${pkg.name}`
);
console.log(`Deleted ${orphanedTools.length} orphaned tools from package: ${pkg.name}`);
}
processed++;