File size: 2,611 Bytes
020ed68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185dcd4
020ed68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
 * Read-only preflight: can we reach every configured cluster, what's in it, and
 * which one will take the next write? Run this before pointing prod anywhere.
 *
 *   node scripts/check-shards.mjs
 */
import { MongoClient } from 'mongodb'
import { readFileSync } from 'node:fs'

// Load .env without a dependency - values may contain '=' so split on the first only.
for (const line of readFileSync(new URL('../.env', import.meta.url), 'utf8').split('\n')) {
  const t = line.trim()
  if (!t || t.startsWith('#')) continue
  const i = t.indexOf('=')
  if (i > 0) process.env[t.slice(0, i).trim()] ??= t.slice(i + 1).trim()
}

const DB_NAME = process.env.MONGO_DB_NAME ?? 'costingDB'
const QUOTA = 512 * 1024 * 1024
const ROLLOVER = 0.9

const urisFor = (prefix) =>
  Object.keys(process.env)
    .filter((k) => new RegExp(`^${prefix}\\d+$`).test(k))
    .sort((a, b) => Number(a.slice(prefix.length)) - Number(b.slice(prefix.length)))
    .map((k) => [k, process.env[k].trim()])

const host = (uri) => uri.match(/@([^/?]+)/)?.[1] ?? '?'

for (const [group, prefix, collection] of [
  ['COSTING', 'CostingDBURL', 'llm_events'],
  ['LAMBDA', 'LambdaDBURL', 'lambda_events'],
]) {
  const uris = urisFor(prefix)
  console.log(`\n=== ${group} — ${uris.length} shard(s), db "${DB_NAME}" ===`)
  if (!uris.length) {
    console.log('  none configured')
    continue
  }

  let writeTarget = null
  for (const [name, uri] of uris) {
    const client = new MongoClient(uri, { serverSelectionTimeoutMS: 15000, maxPoolSize: 2 })
    try {
      await client.connect()
      const db = client.db(DB_NAME)
      const stats = await db.command({ dbStats: 1, scale: 1 })
      const used = (stats.dataSize ?? 0) + (stats.indexSize ?? 0)
      const pct = ((used / QUOTA) * 100).toFixed(1)
      const cols = (await db.listCollections().toArray()).map((c) => c.name)
      const docs = cols.includes(collection)
        ? await db.collection(collection).estimatedDocumentCount()
        : 0
      const open = used < QUOTA * ROLLOVER
      if (open && writeTarget === null) writeTarget = name
      console.log(
        `  ${name.padEnd(15)} ${host(uri).padEnd(38)} ${(used / 1e6).toFixed(1).padStart(7)} MB (${pct.padStart(5)}%)  ` +
          `${collection}=${docs}  collections=[${cols.join(', ') || '-'}]  ${open ? 'OPEN' : 'FULL'}`
      )
    } catch (err) {
      console.log(`  ${name.padEnd(15)} ${host(uri).padEnd(38)} UNREACHABLE: ${String(err).split('\n')[0].slice(0, 90)}`)
    } finally {
      await client.close()
    }
  }
  console.log(`  -> next write goes to: ${writeTarget ?? 'NONE (all full)'}`)
}