MCPcopy Create free account
hub / github.com/AmazingAng/PolyWorld / geocodePending

Function geocodePending

src/lib/sync.ts:37–90  ·  view source on GitHub ↗

Fire-and-forget: geocode pending markets without blocking sync

(db: ReturnType<typeof getDb>)

Source from the content-addressed store, hash-verified

35
36/** Fire-and-forget: geocode pending markets without blocking sync */
37function geocodePending(db: ReturnType<typeof getDb>) {
38 // Watchdog: reset stuck flag after 120s
39 if (geocodeRunning && Date.now() - geocodeStartedAt > GEOCODE_WATCHDOG_MS) {
40 console.warn("[sync] Geocode watchdog: resetting stuck flag");
41 geocodeRunning = false;
42 }
43 if (geocodeRunning) return;
44 const ungeo = db
45 .prepare(`SELECT id, title, description, location FROM events WHERE ai_geo_done = 0 LIMIT 25`)
46 .all() as Array<{ id: string; title: string; description: string | null; location: string | null }>;
47 if (ungeo.length === 0) return;
48
49 const updateGeo = db.prepare(`
50 UPDATE events SET lat = @lat, lng = @lng, location = @location,
51 geo_city = @city, geo_country = @country, ai_geo_done = 1
52 WHERE id = @id
53 `);
54 const markDone = db.prepare(`UPDATE events SET ai_geo_done = 1 WHERE id = ?`);
55
56 const writeResults = (resultMap: Map<string, { id: string; lat: number | null; lng: number | null; location: string | null; city: string | null; country: string | null; confidence: number }> | null) => {
57 try {
58 const txn = db.transaction(() => {
59 for (const market of ungeo) {
60 let result = resultMap?.get(market.id);
61 if (!result || (result.lat === null && result.lng === null)) {
62 const geo = geolocate(market.title, market.description ?? undefined);
63 if (geo) {
64 const [jLat, jLng] = addJitter(geo.coords[0], geo.coords[1], market.id);
65 result = { id: market.id, lat: jLat, lng: jLng, location: geo.location, city: null, country: null, confidence: 0.3 };
66 }
67 }
68 if (result && result.lat !== null && result.lng !== null) {
69 updateGeo.run({ id: market.id, lat: result.lat, lng: result.lng, location: result.location || market.location, city: result.city, country: result.country });
70 } else {
71 markDone.run(market.id);
72 }
73 }
74 });
75 txn();
76 } catch { /* DB busy — will retry next cycle */ }
77 };
78
79 if (isAiConfigured()) {
80 geocodeRunning = true;
81 geocodeStartedAt = Date.now();
82 aiGeocodeBatch(ungeo.map((r) => ({ id: r.id, title: r.title, description: r.description, currentLocation: r.location })))
83 .then((results) => writeResults(new Map(results.map((r) => [r.id, r]))))
84 .catch((err) => { console.error("[sync] Geocode batch failed:", err); writeResults(null); })
85 .finally(() => { geocodeRunning = false; console.info(`[sync] Geocoded ${ungeo.length} markets`); });
86 } else {
87 writeResults(null);
88 console.info(`[sync] Geocoded ${ungeo.length} markets (regex)`);
89 }
90}
91
92export async function runSync(): Promise<{
93 eventCount: number;

Callers 1

runSyncFunction · 0.85

Calls 3

isAiConfiguredFunction · 0.90
aiGeocodeBatchFunction · 0.90
writeResultsFunction · 0.85

Tested by

no test coverage detected