fix: CI indexing
This commit is contained in:
9
.github/workflows/build-database.yml
vendored
9
.github/workflows/build-database.yml
vendored
@@ -58,8 +58,8 @@ jobs:
|
|||||||
INDEX_MODE="${{ github.event.inputs.index_mode || 'full' }}"
|
INDEX_MODE="${{ github.event.inputs.index_mode || 'full' }}"
|
||||||
echo "Index mode: $INDEX_MODE"
|
echo "Index mode: $INDEX_MODE"
|
||||||
|
|
||||||
# Build the index in non-interactive mode
|
# Build the index in non-interactive mode (170m timeout, job timeout is 180m)
|
||||||
timeout 150m node -e "
|
timeout 170m node -e "
|
||||||
const db = require('./lib/database');
|
const db = require('./lib/database');
|
||||||
const dbOps = require('./lib/db-operations');
|
const dbOps = require('./lib/db-operations');
|
||||||
const indexer = require('./lib/indexer');
|
const indexer = require('./lib/indexer');
|
||||||
@@ -73,6 +73,8 @@ jobs:
|
|||||||
if (process.env.GITHUB_TOKEN) {
|
if (process.env.GITHUB_TOKEN) {
|
||||||
dbOps.setSetting('githubToken', process.env.GITHUB_TOKEN);
|
dbOps.setSetting('githubToken', process.env.GITHUB_TOKEN);
|
||||||
console.log('GitHub token configured');
|
console.log('GitHub token configured');
|
||||||
|
} else {
|
||||||
|
console.warn('⚠️ WARNING: No GitHub token found! Rate limit will be 60/hour instead of 5000/hour');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build index
|
// Build index
|
||||||
@@ -92,7 +94,8 @@ jobs:
|
|||||||
" || {
|
" || {
|
||||||
EXIT_CODE=$?
|
EXIT_CODE=$?
|
||||||
if [ $EXIT_CODE -eq 124 ]; then
|
if [ $EXIT_CODE -eq 124 ]; then
|
||||||
echo "Index building timed out after 150 minutes"
|
echo "❌ Index building timed out after 170 minutes"
|
||||||
|
echo "This may indicate rate limiting issues or too many lists to index"
|
||||||
fi
|
fi
|
||||||
exit $EXIT_CODE
|
exit $EXIT_CODE
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,37 @@ function getGitHubToken() {
|
|||||||
return db.getSetting('githubToken', null);
|
return db.getSetting('githubToken', null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check rate limit status proactively
|
||||||
|
async function checkRateLimit() {
|
||||||
|
const token = getGitHubToken();
|
||||||
|
const headers = {
|
||||||
|
'Accept': 'application/vnd.github.v3+json',
|
||||||
|
'User-Agent': 'awesome-cli'
|
||||||
|
};
|
||||||
|
|
||||||
|
if (token) {
|
||||||
|
headers['Authorization'] = `token ${token}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.get('https://api.github.com/rate_limit', {
|
||||||
|
timeout: 5000,
|
||||||
|
headers
|
||||||
|
});
|
||||||
|
|
||||||
|
const core = response.data.resources.core;
|
||||||
|
return {
|
||||||
|
limit: core.limit,
|
||||||
|
remaining: core.remaining,
|
||||||
|
reset: core.reset * 1000,
|
||||||
|
used: core.used
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
// If we can't check rate limit, continue anyway
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Rate-limited request with better handling
|
// Rate-limited request with better handling
|
||||||
async function rateLimitedRequest(url, options = {}) {
|
async function rateLimitedRequest(url, options = {}) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
@@ -22,6 +53,26 @@ async function rateLimitedRequest(url, options = {}) {
|
|||||||
await new Promise(resolve => setTimeout(resolve, RATE_LIMIT_DELAY - timeSinceLastRequest));
|
await new Promise(resolve => setTimeout(resolve, RATE_LIMIT_DELAY - timeSinceLastRequest));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check rate limit proactively every 50 requests
|
||||||
|
if (Math.random() < 0.02) { // 2% chance = roughly every 50 requests
|
||||||
|
const rateLimitStatus = await checkRateLimit();
|
||||||
|
if (rateLimitStatus && rateLimitStatus.remaining < 10) {
|
||||||
|
const waitTime = Math.max(0, rateLimitStatus.reset - Date.now());
|
||||||
|
const waitMinutes = Math.ceil(waitTime / 60000);
|
||||||
|
|
||||||
|
console.log();
|
||||||
|
console.log(chalk.yellow(`⚠️ Rate limit low: ${rateLimitStatus.remaining}/${rateLimitStatus.limit} remaining`));
|
||||||
|
console.log(chalk.yellow(` Proactively waiting ${waitMinutes} minutes to avoid exhausting limit...`));
|
||||||
|
|
||||||
|
const isCI = process.env.CI === 'true';
|
||||||
|
if (isCI) {
|
||||||
|
console.log(chalk.cyan('🤖 CI mode: automatically waiting...'));
|
||||||
|
await new Promise(resolve => setTimeout(resolve, waitTime + 30000)); // 30s buffer
|
||||||
|
console.log(chalk.green('✓ Rate limit reset, resuming...'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lastRequestTime = Date.now();
|
lastRequestTime = Date.now();
|
||||||
|
|
||||||
const token = getGitHubToken();
|
const token = getGitHubToken();
|
||||||
@@ -50,9 +101,15 @@ async function rateLimitedRequest(url, options = {}) {
|
|||||||
const waitMinutes = Math.ceil(waitTime / 60000);
|
const waitMinutes = Math.ceil(waitTime / 60000);
|
||||||
|
|
||||||
if (remaining === '0' || remaining === 0) {
|
if (remaining === '0' || remaining === 0) {
|
||||||
|
const rateLimit = error.response.headers['x-ratelimit-limit'];
|
||||||
|
const resetDate = new Date(resetTime).toISOString();
|
||||||
|
|
||||||
console.log();
|
console.log();
|
||||||
console.log(chalk.red('⚠️ GitHub API Rate Limit Exceeded!'));
|
console.log(chalk.red('⚠️ GitHub API Rate Limit Exceeded!'));
|
||||||
|
console.log(chalk.yellow(` Rate limit: ${rateLimit} requests/hour`));
|
||||||
|
console.log(chalk.yellow(` Reset at: ${resetDate}`));
|
||||||
console.log(chalk.yellow(` Wait time: ${waitMinutes} minutes`));
|
console.log(chalk.yellow(` Wait time: ${waitMinutes} minutes`));
|
||||||
|
console.log(chalk.gray(` Token status: ${token ? 'USING TOKEN ✓' : 'NO TOKEN ✗'}`));
|
||||||
|
|
||||||
if (!token && !rateLimitWarningShown) {
|
if (!token && !rateLimitWarningShown) {
|
||||||
console.log();
|
console.log();
|
||||||
@@ -93,9 +150,13 @@ async function rateLimitedRequest(url, options = {}) {
|
|||||||
} else if (action === 'skip') {
|
} else if (action === 'skip') {
|
||||||
throw new Error('SKIP_RATE_LIMIT'); // Special error to skip
|
throw new Error('SKIP_RATE_LIMIT'); // Special error to skip
|
||||||
} else {
|
} else {
|
||||||
// Wait with countdown
|
// Wait with countdown and add 30 second buffer to ensure rate limit has fully reset
|
||||||
console.log(chalk.gray(`\nWaiting ${waitMinutes} minutes...`));
|
const bufferTime = 30000; // 30 seconds
|
||||||
await new Promise(resolve => setTimeout(resolve, waitTime + 1000));
|
const totalWaitTime = waitTime + bufferTime;
|
||||||
|
const totalWaitMinutes = Math.ceil(totalWaitTime / 60000);
|
||||||
|
console.log(chalk.gray(`\nWaiting ${totalWaitMinutes} minutes (including 30s buffer)...`));
|
||||||
|
await new Promise(resolve => setTimeout(resolve, totalWaitTime));
|
||||||
|
console.log(chalk.green('✓ Rate limit should be reset, resuming...'));
|
||||||
return rateLimitedRequest(url, options);
|
return rateLimitedRequest(url, options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,5 +284,6 @@ module.exports = {
|
|||||||
getLatestCommit,
|
getLatestCommit,
|
||||||
getAwesomeListsIndex,
|
getAwesomeListsIndex,
|
||||||
parseGitHubUrl,
|
parseGitHubUrl,
|
||||||
rateLimitedRequest
|
rateLimitedRequest,
|
||||||
|
getRateLimitStatus: checkRateLimit
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -202,6 +202,27 @@ async function buildIndex(force = false, mode = null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check rate limit status before starting
|
||||||
|
try {
|
||||||
|
const rateLimitInfo = await github.getRateLimitStatus();
|
||||||
|
if (rateLimitInfo) {
|
||||||
|
console.log(chalk.cyan('📊 GitHub API Rate Limit Status:'));
|
||||||
|
console.log(chalk.gray(` Limit: ${rateLimitInfo.limit} requests/hour`));
|
||||||
|
console.log(chalk.gray(` Remaining: ${rateLimitInfo.remaining}/${rateLimitInfo.limit}`));
|
||||||
|
console.log(chalk.gray(` Used: ${rateLimitInfo.used}`));
|
||||||
|
console.log(chalk.gray(` Resets at: ${new Date(rateLimitInfo.reset).toISOString()}`));
|
||||||
|
console.log();
|
||||||
|
|
||||||
|
if (rateLimitInfo.limit === 60) {
|
||||||
|
console.log(chalk.yellow('⚠️ WARNING: Using unauthenticated rate limit (60/hour)'));
|
||||||
|
console.log(chalk.yellow(' This will likely not be enough to complete indexing'));
|
||||||
|
console.log();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(chalk.gray('Could not check rate limit status, continuing...'));
|
||||||
|
}
|
||||||
|
|
||||||
console.log(pinkPurple(`\n✨ Starting index of ${listsToIndex.length} awesome lists ✨\n`));
|
console.log(pinkPurple(`\n✨ Starting index of ${listsToIndex.length} awesome lists ✨\n`));
|
||||||
|
|
||||||
// Progress bars
|
// Progress bars
|
||||||
|
|||||||
Reference in New Issue
Block a user