Enhanced Features Guide v2.0

This guide provides a deep dive into each of the six major features added in version 2.0, with technical details, usage examples, and best practices.


šŸ“‘ Table of Contents

  1. Resume Capability
  2. Smart Rate Limiting
  3. Automatic Retries
  4. Progress Tracking
  5. Detailed Logging
  6. Error Recovery

1. Resume Capability

Overview

The resume feature saves your progress every 10 posts, allowing you to continue exactly where you left off if the script is interrupted for any reason.

How It Works

Checkpoint System:

markCompleted(filePath) {
  this.completed.push(filePath);
  this.statistics.generated++;
  
  // Save checkpoint every 10 posts
  if (this.completed.length % 10 === 0) {
    this.save();
    log(`Checkpoint saved: ${this.completed.length} posts completed`);
  }
}

Progress File Structure:

{
  "startTime": 1732788600000,
  "completed": [
    "C:\\dev\\itblogpros\\posts\\2025-01-15-wifi-7.md",
    "C:\\dev\\itblogpros\\posts\\2025-01-16-smart-home.md",
    "..."
  ],
  "failed": [],
  "skipped": [],
  "totalProcessed": 250,
  "lastCheckpoint": "2025-11-28T10:35:00.000Z",
  "statistics": {
    "generated": 240,
    "errors": 0,
    "retries": 8,
    "apiCalls": 248
  }
}

Usage Examples

Normal Run (No Resume):

node generate-meta-descriptions-gemini.js --write

Creates .meta-generation-progress.json and saves every 10 posts.

Resume After Interruption:

node generate-meta-descriptions-gemini.js --resume --write

Loads progress file and continues from last checkpoint.

Check Progress Manually:

Get-Content .meta-generation-progress.json | ConvertFrom-Json

Interruption Scenarios

Power Outage:

Internet Drop:

Manual Stop (Ctrl+C):

File Management

Progress File Location:

C:\dev\itblogpros\.meta-generation-progress.json

Cleanup: The progress file is automatically deleted when:

Manual Cleanup:

# Windows
del .meta-generation-progress.json

# Linux/Mac
rm .meta-generation-progress.json

Best Practices

āœ… DO:

āŒ DON'T:


2. Smart Rate Limiting

Overview

Intelligent rate limit monitoring that ensures you stay under the 15 RPM free tier limit without wasting time on unnecessary delays.

How It Works

RateLimiter Class:

class RateLimiter {
  constructor(requestsPerMinute) {
    this.requestsPerMinute = requestsPerMinute;  // 12 (conservative)
    this.requests = [];  // Timestamps of recent requests
  }

  async waitIfNeeded() {
    const now = Date.now();
    const oneMinuteAgo = now - 60000;
    
    // Remove requests older than 60 seconds
    this.requests = this.requests.filter(time => time > oneMinuteAgo);
    
    // Check if we're at the limit
    if (this.requests.length >= this.requestsPerMinute) {
      const oldestRequest = this.requests[0];
      const waitTime = 60000 - (now - oldestRequest) + 1000;  // +1s buffer
      
      if (waitTime > 0) {
        log(`Rate limit approaching, waiting ${Math.round(waitTime / 1000)}s...`);
        await sleep(waitTime);
      }
    }
    
    // Record this request
    this.requests.push(now);
  }
}

Configuration

Default Settings:

const CONFIG = {
  requestsPerMinute: 12,       // Conservative (limit is 15)
  delayBetweenRequests: 5500,  // 5.5 seconds
  // ...
};

Why 12 RPM instead of 15?

Rate Limit Strategy

Request Pattern:

Second 0:  Request 1  (0s)
Second 5:  Request 2  (5.5s delay)
Second 10: Request 3  (5.5s delay)
Second 15: Request 4  (5.5s delay)
...
Second 55: Request 12 (5.5s delay)
Second 60: Window resets, Request 13 starts new minute

Actual Rate:

Monitoring

Console Output:

[2025-11-28T10:30:05.200Z] API call 1: Generating...
[2025-11-28T10:30:10.700Z] API call 2: Generating...
[2025-11-28T10:30:16.200Z] API call 3: Generating...
...
[2025-11-28T10:31:05.200Z] Rate limit approaching, waiting 3s...
[2025-11-28T10:31:08.200Z] API call 13: Generating...

Adjustment Options

More Conservative (10 RPM):

const CONFIG = {
  requestsPerMinute: 10,
  delayBetweenRequests: 6000,  // 6 seconds
};

Closer to Limit (14 RPM):

const CONFIG = {
  requestsPerMinute: 14,
  delayBetweenRequests: 4300,  // 4.3 seconds
};

Not Recommended: Setting to 15 RPM exactly. Always leave buffer.

Best Practices

āœ… DO:

āŒ DON'T:


3. Automatic Retries

Overview

Intelligent retry logic that handles temporary failures with exponential backoff, dramatically improving success rates.

How It Works

Retry Function:

async function generateMetaDescription(title, content, retryCount = 0) {
  try {
    await rateLimiter.waitIfNeeded();
    progress.statistics.apiCalls++;

    const result = await model.generateContent(prompt);
    let description = response.text().trim();

    // Validate length
    if (description.length < CONFIG.minLength) {
      if (retryCount < CONFIG.maxRetries) {
        log(`Description too short (${description.length} chars), retrying...`);
        progress.statistics.retries++;
        
        // Exponential backoff
        const delay = CONFIG.retryDelay * Math.pow(CONFIG.retryBackoffMultiplier, retryCount);
        await sleep(delay);
        
        return generateMetaDescription(title, content, retryCount + 1);
      } else {
        throw new Error(`Too short after ${CONFIG.maxRetries} attempts`);
      }
    }

    return description;

  } catch (error) {
    // Retry on specific errors
    if (retryCount < CONFIG.maxRetries && isRetryableError(error)) {
      const delay = CONFIG.retryDelay * Math.pow(CONFIG.retryBackoffMultiplier, retryCount);
      log(`Error: ${error.message}, waiting ${delay/1000}s before retry ${retryCount + 1}...`);
      progress.statistics.retries++;
      
      await sleep(delay);
      return generateMetaDescription(title, content, retryCount + 1);
    }
    
    throw error;
  }
}

Retry Conditions

Retryable Errors:

  1. Rate Limit (429): API quota temporarily exceeded
  2. Network Timeouts: Connection issues
  3. Short Descriptions: Generated text < 120 chars
  4. Temporary API Issues: Service unavailable

Non-Retryable Errors:

  1. Invalid API Key: Authentication failure
  2. Malformed Request: Code bug
  3. Content Policy Violation: Blocked content

Backoff Strategy

Exponential Delays:

Attempt 1: Generate → Fail
Wait: 10 seconds
Attempt 2: Generate → Fail
Wait: 20 seconds
Attempt 3: Generate → Fail
Wait: 40 seconds
Attempt 4: Give up, mark as failed

Why Exponential?

Configuration

const CONFIG = {
  maxRetries: 3,                  // Up to 3 retry attempts
  retryDelay: 10000,             // 10 seconds initial
  retryBackoffMultiplier: 2,     // Double each time
  // ...
};

Total Wait Time:

Logging

[2025-11-28T10:30:05.200Z] API call 1: Generating for "WiFi 7..."
[2025-11-28T10:30:07.200Z] āœ— Description too short (95 chars), retrying...
[2025-11-28T10:30:17.200Z] API call 2: Retry 1/3 for "WiFi 7..."
[2025-11-28T10:30:19.200Z] āœ“ Generated (145 chars): Discover if WiFi 7...

Success Rates

Without Retries (v1.0):

With Retries (v2.0):

Improvement: 87.5% reduction in failures

Best Practices

āœ… DO:

āŒ DON'T:


4. Progress Tracking

Overview

Comprehensive tracking of all processing activity, enabling resume capability and detailed reporting.

Data Structure

ProgressTracker Class:

class ProgressTracker {
  constructor() {
    this.startTime = Date.now();
    this.completed = [];     // Successfully processed files
    this.failed = [];        // Failed files with reasons
    this.skipped = [];       // Skipped files with reasons
    this.statistics = {
      generated: 0,          // New descriptions created
      errors: 0,             // Total errors
      retries: 0,            // Total retry attempts
      apiCalls: 0            // Total API calls made
    };
  }
}

Saved Progress File

Location: .meta-generation-progress.json

Full Structure:

{
  "startTime": 1732788600000,
  "completed": [
    "C:\\dev\\itblogpros\\posts\\2025-01-15-wifi-7.md",
    "C:\\dev\\itblogpros\\posts\\2025-01-16-smart-home.md",
    "C:\\dev\\itblogpros\\posts\\2025-01-17-router-guide.md"
  ],
  "failed": [
    {
      "filePath": "C:\\dev\\itblogpros\\posts\\2023-05-10-old-post.md",
      "reason": "API timeout after 3 retries",
      "timestamp": "2025-11-28T10:25:00.000Z"
    }
  ],
  "skipped": [
    {
      "filePath": "C:\\dev\\itblogpros\\posts\\2025-01-20-already-good.md",
      "reason": "has good description"
    }
  ],
  "totalProcessed": 558,
  "lastCheckpoint": "2025-11-28T10:42:00.000Z",
  "statistics": {
    "generated": 408,
    "errors": 1,
    "retries": 12,
    "apiCalls": 421
  }
}

Tracking Methods

Mark Completed:

progress.markCompleted(filePath);
// Adds to completed array
// Increments generated count
// Saves checkpoint every 10

Mark Failed:

progress.markFailed(filePath, reason);
// Adds to failed array with timestamp
// Increments error count

Mark Skipped:

progress.markSkipped(filePath, reason);
// Adds to skipped array with reason
// Doesn't count as error

Check if Processed:

if (progress.isProcessed(filePath)) {
  // Skip this file when resuming
}

Statistics Tracking

Incremented Automatically:

progress.statistics.apiCalls++;      // Every API call
progress.statistics.retries++;       // Every retry
progress.statistics.generated++;     // Every success
progress.statistics.errors++;        // Every failure

Summary Generation

const summary = progress.getSummary();
// Returns:
{
  completed: 408,
  failed: 1,
  skipped: 150,
  total: 559,
  statistics: { ... },
  timeSeconds: 720,
  timeMinutes: 12
}

Checkpoint Frequency

Every 10 Posts:

Post 10:  āœ“ Checkpoint saved
Post 20:  āœ“ Checkpoint saved
Post 30:  āœ“ Checkpoint saved
...
Post 550: āœ“ Checkpoint saved
Post 558: āœ“ Final save & cleanup

Why Every 10?

Best Practices

āœ… DO:

āŒ DON'T:


5. Detailed Logging

Overview

Comprehensive logging system that creates a permanent audit trail of all processing activity.

Log File

Location: meta-generation.log

Format:

[ISO 8601 Timestamp] Message

What Gets Logged

Startup:

[2025-11-28T10:30:00.000Z] ================================================================
[2025-11-28T10:30:00.000Z] Meta Description Generator v2.0 - Started
[2025-11-28T10:30:00.100Z] Mode: WRITE, Resume: false, Limit: none
[2025-11-28T10:30:00.100Z] ================================================================
[2025-11-28T10:30:00.200Z] Processing 558 posts...

API Calls:

[2025-11-28T10:30:05.800Z] API call 1: Generating for "WiFi 7 vs WiFi 6: Should You..."
[2025-11-28T10:30:07.200Z] āœ“ Generated (145 chars): Discover if WiFi 7 is worth upgrading...
[2025-11-28T10:30:07.300Z] āœ“ Updated: 2025-01-15-wifi-7-vs-wifi-6.md

Skipped Posts:

[2025-11-28T10:30:13.400Z] [2/558] Processing: 2025-01-16-smart-home.md
[2025-11-28T10:30:13.500Z] ⊘ Skipped "AI Home Assistants..." - already has good description

Retries:

[2025-11-28T10:30:20.100Z] API call 3: Generating for "Old Post Title..."
[2025-11-28T10:30:21.500Z] Description too short (95 chars), retrying...
[2025-11-28T10:30:31.500Z] API call 4: Retry 1/3 for "Old Post Title..."
[2025-11-28T10:30:33.100Z] āœ“ Generated (142 chars): Learn how to troubleshoot...

Rate Limiting:

[2025-11-28T10:31:05.200Z] Rate limit approaching, waiting 3s...
[2025-11-28T10:31:08.200Z] API call 13: Generating for "Next Post..."

Checkpoints:

[2025-11-28T10:35:00.000Z] Checkpoint saved: 50 posts completed
[2025-11-28T10:40:00.000Z] Checkpoint saved: 100 posts completed

Errors:

[2025-11-28T10:37:15.300Z] āœ— Error processing 2023-03-15-broken-post.md: Invalid front matter
[2025-11-28T10:37:15.400Z] āš ļø  Consecutive errors: 1/5

Summary:

[2025-11-28T10:42:00.000Z] =====================================
[2025-11-28T10:42:00.000Z] SUMMARY
[2025-11-28T10:42:00.000Z] =====================================
[2025-11-28T10:42:00.000Z] āœ“ Successfully generated: 408
[2025-11-28T10:42:00.000Z] ⊘ Skipped (already good): 150
[2025-11-28T10:42:00.000Z] āœ— Errors: 0
[2025-11-28T10:42:00.000Z] ↻ Total retries: 12
[2025-11-28T10:42:00.000Z] ā—Ž API calls made: 420
[2025-11-28T10:42:00.000Z] āŠ• Total processed: 558
[2025-11-28T10:42:00.000Z] ā±  Time taken: 720s (~12 minutes)
[2025-11-28T10:42:00.000Z] šŸ’° Cost: $0.00 (FREE Gemini Flash API)

Log Analysis

View Recent Errors:

Select-String "āœ— Error" meta-generation.log

Count Retries:

(Select-String "Retry" meta-generation.log).Count

Check Rate Limiting:

Select-String "Rate limit" meta-generation.log

View Summary:

Select-String "SUMMARY" -Context 0,10 meta-generation.log

Log Rotation

Not Automatic: Log file appends indefinitely.

Manual Cleanup:

# Archive old log
mv meta-generation.log meta-generation-2025-11-28.log

# Or delete
rm meta-generation.log

When to Clean:

Best Practices

āœ… DO:

āŒ DON'T:


6. Error Recovery

Overview

Graceful error handling that prevents API quota waste and provides clear recovery instructions.

Consecutive Error Detection

let consecutiveErrors = 0;
const maxConsecutiveErrors = 5;

for (const file of files) {
  const result = await processPost(file);
  
  if (result.error) {
    consecutiveErrors++;
    
    if (consecutiveErrors >= maxConsecutiveErrors) {
      log('\nāš ļø  Stopping after 5 consecutive errors');
      log('Progress has been saved. Fix the issue and run with --resume flag.');
      progress.save();
      break;
    }
  } else {
    consecutiveErrors = 0;  // Reset on success
  }
}

Why Stop at 5?

Prevents:

Allows:

Error Scenarios

Network Outage:

Post 100: āœ— Network timeout
Post 101: āœ— Network timeout
Post 102: āœ— Network timeout
Post 103: āœ— Network timeout
Post 104: āœ— Network timeout
āš ļø  Stopping after 5 consecutive errors
Progress saved to .meta-generation-progress.json
Fix network and run: --resume --write

Invalid API Key:

Post 1: āœ— Authentication failed
Post 2: āœ— Authentication failed
Post 3: āœ— Authentication failed
Post 4: āœ— Authentication failed
Post 5: āœ— Authentication failed
āš ļø  Stopping after 5 consecutive errors
Fix API key and run: --resume --write

Mixed Errors (Continues):

Post 50:  āœ“ Success (resets counter)
Post 51:  āœ— Network timeout (count: 1)
Post 52:  āœ“ Success (resets counter)
Post 53:  āœ— Short description (count: 1)
Post 54:  āœ“ Success (resets counter)
... processing continues ...

Recovery Instructions

Displayed on Error Stop:

āš ļø  Stopping after 5 consecutive errors

Common Issues:
1. Network Down
   → Check internet connection
   → Resume with: --resume --write

2. Invalid API Key
   → Verify key at: https://makersuite.google.com
   → Set: $env:GEMINI_API_KEY="key"
   → Resume with: --resume --write

3. Rate Limit Exhausted
   → Wait 1 hour
   → Resume with: --resume --write

Progress saved. No work lost.
Last successful: Post 99
Will resume at: Post 100

Manual Recovery

Check Progress:

Get-Content .meta-generation-progress.json | ConvertFrom-Json

Review Logs:

type meta-generation.log | Select-String "Error"

Resume After Fix:

node generate-meta-descriptions-gemini.js --resume --write

Best Practices

āœ… DO:

āŒ DON'T:


šŸŽÆ Summary

All six enhanced features work together to provide:

  1. Resume Capability → Never lose work
  2. Smart Rate Limiting → Stay under limits automatically
  3. Automatic Retries → 87.5% fewer failures
  4. Progress Tracking → Full visibility
  5. Detailed Logging → Complete audit trail
  6. Error Recovery → Intelligent handling

Result: Production-ready, reliable, professional-quality tool. šŸš€


For implementation details, see IMPLEMENTATION-GUIDE-GEMINI.md