The job_run_logs table tracks scheduled job orchestration, not individual worker jobs. Worker info (worker_id, worker_hostname) belongs on dispensary_crawl_jobs, not job_run_logs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
126 lines
4.9 KiB
JavaScript
126 lines
4.9 KiB
JavaScript
"use strict";
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.lookupProxyLocation = lookupProxyLocation;
|
|
exports.updateProxyLocation = updateProxyLocation;
|
|
exports.updateAllProxyLocations = updateAllProxyLocations;
|
|
exports.queueProxyLocationUpdate = queueProxyLocationUpdate;
|
|
const axios_1 = __importDefault(require("axios"));
|
|
const migrate_1 = require("../db/migrate");
|
|
// Free API - 45 requests/minute limit
|
|
const GEOLOCATION_API = 'http://ip-api.com/json/';
|
|
async function lookupProxyLocation(host) {
|
|
try {
|
|
const response = await axios_1.default.get(`${GEOLOCATION_API}${host}?fields=status,message,country,countryCode,regionName,city,query`);
|
|
const data = response.data;
|
|
if (data.status === 'fail') {
|
|
console.log(`❌ Geolocation lookup failed for ${host}: ${data.message}`);
|
|
return null;
|
|
}
|
|
return data;
|
|
}
|
|
catch (error) {
|
|
console.error(`❌ Error looking up location for ${host}:`, error.message);
|
|
return null;
|
|
}
|
|
}
|
|
async function updateProxyLocation(proxyId, location) {
|
|
await migrate_1.pool.query(`
|
|
UPDATE proxies
|
|
SET city = $1,
|
|
state = $2,
|
|
country = $3,
|
|
country_code = $4,
|
|
location_updated_at = CURRENT_TIMESTAMP
|
|
WHERE id = $5
|
|
`, [
|
|
location.city,
|
|
location.regionName,
|
|
location.country,
|
|
location.countryCode,
|
|
proxyId
|
|
]);
|
|
}
|
|
async function updateAllProxyLocations(batchSize = 45) {
|
|
console.log('🌍 Starting proxy location update job...');
|
|
// Get all proxies without location data
|
|
const result = await migrate_1.pool.query(`
|
|
SELECT id, host
|
|
FROM proxies
|
|
WHERE location_updated_at IS NULL
|
|
OR location_updated_at < CURRENT_TIMESTAMP - INTERVAL '30 days'
|
|
ORDER BY id
|
|
`);
|
|
const proxies = result.rows;
|
|
console.log(`📊 Found ${proxies.length} proxies to update`);
|
|
let updated = 0;
|
|
let failed = 0;
|
|
// Process in batches to respect rate limit (45 req/min)
|
|
for (let i = 0; i < proxies.length; i += batchSize) {
|
|
const batch = proxies.slice(i, i + batchSize);
|
|
console.log(`🔄 Processing batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(proxies.length / batchSize)} (${batch.length} proxies)`);
|
|
// Process batch
|
|
for (const proxy of batch) {
|
|
const location = await lookupProxyLocation(proxy.host);
|
|
if (location) {
|
|
await updateProxyLocation(proxy.id, location);
|
|
console.log(`✅ Updated ${proxy.id}: ${location.city}, ${location.regionName} - ${location.country}`);
|
|
updated++;
|
|
}
|
|
else {
|
|
console.log(`⚠️ Failed to get location for proxy ${proxy.id} (${proxy.host})`);
|
|
failed++;
|
|
}
|
|
// Small delay between requests
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
// Wait 60 seconds before next batch to respect rate limit
|
|
if (i + batchSize < proxies.length) {
|
|
console.log(`⏳ Waiting 60s before next batch (rate limit: 45 req/min)...`);
|
|
await new Promise(resolve => setTimeout(resolve, 60000));
|
|
}
|
|
}
|
|
console.log(`✅ Proxy location update complete!`);
|
|
console.log(` Updated: ${updated}`);
|
|
console.log(` Failed: ${failed}`);
|
|
}
|
|
// Queue for background processing
|
|
const locationUpdateQueue = new Set();
|
|
let isProcessing = false;
|
|
function queueProxyLocationUpdate(proxyId) {
|
|
locationUpdateQueue.add(proxyId);
|
|
processLocationQueue();
|
|
}
|
|
async function processLocationQueue() {
|
|
if (isProcessing || locationUpdateQueue.size === 0)
|
|
return;
|
|
isProcessing = true;
|
|
try {
|
|
const proxyIds = Array.from(locationUpdateQueue);
|
|
locationUpdateQueue.clear();
|
|
console.log(`🌍 Processing ${proxyIds.length} proxy location updates from queue`);
|
|
for (const proxyId of proxyIds) {
|
|
const result = await migrate_1.pool.query('SELECT host FROM proxies WHERE id = $1', [proxyId]);
|
|
if (result.rows.length === 0)
|
|
continue;
|
|
const host = result.rows[0].host;
|
|
const location = await lookupProxyLocation(host);
|
|
if (location) {
|
|
await updateProxyLocation(proxyId, location);
|
|
console.log(`✅ Queue: Updated ${proxyId}: ${location.city}, ${location.regionName} - ${location.country}`);
|
|
}
|
|
// Respect rate limit
|
|
await new Promise(resolve => setTimeout(resolve, 1500)); // ~40 req/min
|
|
}
|
|
}
|
|
finally {
|
|
isProcessing = false;
|
|
// Process any new items that were added while we were processing
|
|
if (locationUpdateQueue.size > 0) {
|
|
processLocationQueue();
|
|
}
|
|
}
|
|
}
|