Sync system was timing out because discovery endpoints (keyword, changes) also ran schema extraction (~10-15s per tool). Now discovery is fast (npm metadata + DB writes only) and a new /api/sync/enrich endpoint handles schema extraction in time-budgeted chunks. Railway executor was crashing without restarting due to unhandled promise rejections, no restart policy, and no health checks. Added crash protection, graceful shutdown, cache size limits, railway.toml with ALWAYS restart policy, and upgraded Deno from 1.39 to 2.1.9. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
114 lines
4.9 KiB
YAML
114 lines
4.9 KiB
YAML
name: Sync Tool Enrichment
|
|
|
|
on:
|
|
schedule:
|
|
# Run every 2 minutes
|
|
- cron: '*/2 * * * *'
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
sync-enrich:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Trigger enrichment sync
|
|
id: sync
|
|
run: |
|
|
# Call the sync API and capture response
|
|
response=$(curl -X POST "${{ secrets.VERCEL_PRODUCTION_URL }}/api/sync/enrich" \
|
|
-H "Authorization: Bearer ${{ secrets.CRON_SECRET }}" \
|
|
-H "Content-Type: application/json" \
|
|
-f -s -S)
|
|
|
|
echo "Response: $response"
|
|
|
|
# Extract data using jq
|
|
enriched=$(echo "$response" | jq -r '.data.enriched')
|
|
discovered=$(echo "$response" | jq -r '.data.discovered')
|
|
skipped=$(echo "$response" | jq -r '.data.skipped')
|
|
errors=$(echo "$response" | jq -r '.data.errors')
|
|
durationMs=$(echo "$response" | jq -r '.data.durationMs')
|
|
|
|
# Extract and display error messages
|
|
errorMessages=$(echo "$response" | jq -r '.data.errorMessages[]?' 2>/dev/null || echo "")
|
|
|
|
if [ -n "$errorMessages" ]; then
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "⚠️ ENRICHMENT ERRORS ($errors total):"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "$response" | jq -r '.data.errorMessages[]?' | while IFS= read -r error; do
|
|
echo " • $error"
|
|
done
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
fi
|
|
|
|
# Set outputs for Discord notification
|
|
echo "enriched=$enriched" >> $GITHUB_OUTPUT
|
|
echo "discovered=$discovered" >> $GITHUB_OUTPUT
|
|
echo "skipped=$skipped" >> $GITHUB_OUTPUT
|
|
echo "errors=$errors" >> $GITHUB_OUTPUT
|
|
echo "durationMs=$durationMs" >> $GITHUB_OUTPUT
|
|
|
|
# Store error messages for Discord (first 3, truncated)
|
|
if [ "$errors" -gt 0 ]; then
|
|
errorSummary=$(echo "$response" | jq -r '.data.errorMessages[0:3]? | join("\n• ")' 2>/dev/null || echo "")
|
|
if [ -n "$errorSummary" ]; then
|
|
echo "• $errorSummary" > /tmp/error_summary.txt
|
|
fi
|
|
fi
|
|
|
|
# Determine status emoji
|
|
if [ "$errors" -gt 0 ]; then
|
|
echo "status_emoji=⚠️" >> $GITHUB_OUTPUT
|
|
echo "status_color=16776960" >> $GITHUB_OUTPUT # Yellow
|
|
else
|
|
echo "status_emoji=✅" >> $GITHUB_OUTPUT
|
|
echo "status_color=5763719" >> $GITHUB_OUTPUT # Green
|
|
fi
|
|
|
|
- name: Send Discord notification
|
|
if: always()
|
|
run: |
|
|
# Format duration
|
|
duration_sec=$(echo "scale=2; ${{ steps.sync.outputs.durationMs }} / 1000" | bc)
|
|
|
|
# Build Discord payload using jq for proper JSON escaping
|
|
error_text=""
|
|
|
|
if [ -f /tmp/error_summary.txt ] && [ ${{ steps.sync.outputs.errors }} -gt 0 ]; then
|
|
error_text=$(cat /tmp/error_summary.txt | head -c 800)
|
|
fi
|
|
|
|
# Build fields array dynamically
|
|
base_fields='[
|
|
{ "name": "🔧 Enriched", "value": "${{ steps.sync.outputs.enriched }}", "inline": true },
|
|
{ "name": "🔍 Discovered", "value": "${{ steps.sync.outputs.discovered }}", "inline": true },
|
|
{ "name": "⏭️ Skipped", "value": "${{ steps.sync.outputs.skipped }}", "inline": true },
|
|
{ "name": "❌ Errors", "value": "${{ steps.sync.outputs.errors }}", "inline": true },
|
|
{ "name": "⏱️ Duration", "value": "'"${duration_sec}s"'", "inline": true },
|
|
{ "name": "🔗 Run", "value": "[View Logs](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})", "inline": true }
|
|
]'
|
|
|
|
# Create payload with dynamic fields
|
|
payload=$(jq -n \
|
|
--arg title "${{ steps.sync.outputs.status_emoji }} Tool Enrichment Sync" \
|
|
--argjson color ${{ steps.sync.outputs.status_color }} \
|
|
--argjson baseFields "$base_fields" \
|
|
--arg error_text "$error_text" \
|
|
--arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%S.000Z)" \
|
|
'
|
|
{
|
|
embeds: [{
|
|
title: $title,
|
|
color: $color,
|
|
fields: (
|
|
$baseFields +
|
|
(if $error_text != "" then [{ name: "🔍 Error Details", value: ("```\n" + $error_text + "\n```"), inline: false }] else [] end)
|
|
),
|
|
timestamp: $timestamp
|
|
}]
|
|
}')
|
|
|
|
# Send to Discord
|
|
curl -X POST "${{ secrets.DISCORD_WEBHOOK }}" \
|
|
-H "Content-Type: application/json" \
|
|
-d "$payload"
|