"""Restart testdatadb service, rerun backfill on remaining ~438 records, verify.""" import base64, subprocess, yaml, paramiko HOST='192.168.0.6'; USER='sysadmin' NODE_BACKFILL = r''' const fs = require('fs'); const path = require('path'); const db = require('./database/db'); const { loadAllSpecs, getSpecs } = require('./parsers/spec-reader'); const { generateExactDatasheet } = require('./templates/datasheet-exact'); const OUTPUT_DIR = '\\\\ad2\\webshare\\For_Web'; (async () => { if (!fs.existsSync(OUTPUT_DIR)) { console.error('[FAIL] output dir not reachable'); process.exit(1); } const specMap = loadAllSpecs(); const where = "overall_result='PASS' AND forweb_exported_at IS NULL " + "AND ((model_number LIKE 'SCMVAS%' OR model_number LIKE 'SCMHVAS%' OR model_number LIKE 'VAS-M%' OR model_number LIKE 'HVAS-M%') OR log_type='VASLOG_ENG')"; const rows = await db.query('SELECT * FROM test_records WHERE ' + where + ' ORDER BY test_date DESC'); console.log('[INFO] ' + rows.length + ' records to process'); let rendered = 0, passthrough = 0, skipped = 0, errors = 0; const batchIds = []; async function flush() { if (!batchIds.length) return; const now = new Date().toISOString(); await db.transaction(async tx => { for (const id of batchIds) await tx.execute('UPDATE test_records SET forweb_exported_at=$1 WHERE id=$2',[now,id]); }); batchIds.length = 0; } for (const r of rows) { try { const outPath = path.join(OUTPUT_DIR, r.serial_number + '.TXT'); if (r.log_type === 'VASLOG_ENG') { if (r.source_file && fs.existsSync(r.source_file)) fs.copyFileSync(r.source_file, outPath); else fs.writeFileSync(outPath, r.raw_data || '', 'utf8'); passthrough++; } else { const specs = getSpecs(specMap, r.model_number); if (!specs) { skipped++; continue; } const txt = generateExactDatasheet(r, specs); if (!txt) { skipped++; continue; } fs.writeFileSync(outPath, txt, 'utf8'); rendered++; } batchIds.push(r.id); if (batchIds.length >= 100) { await flush(); process.stdout.write('[PROGRESS] ' + (rendered+passthrough) + '/' + rows.length + '\n'); } } catch (e) { errors++; console.error('[ERR] ' + r.serial_number + ': ' + e.message); } } await flush(); console.log('\n========================================'); console.log('Straggler Backfill Complete'); console.log('========================================'); console.log('Rendered: ' + rendered); console.log('Passthrough: ' + passthrough); console.log('Skipped: ' + skipped); console.log('Errors: ' + errors); // Post-run count const remaining = await db.queryOne("SELECT COUNT(*) c FROM test_records WHERE " + where); console.log('Remaining backlog: ' + remaining.c); // Sample a plain-decimal-derived datasheet to verify render const sample = await db.queryOne( "SELECT serial_number, model_number FROM test_records WHERE forweb_exported_at IS NOT NULL " + "AND raw_data LIKE '%PASS .%' AND (model_number LIKE 'SCMVAS%' OR model_number LIKE 'SCMHVAS%') " + "ORDER BY forweb_exported_at DESC LIMIT 1" ); if (sample) console.log('Plain-decimal sample just rendered: SN=' + sample.serial_number + ' model=' + sample.model_number); await db.close(); })().catch(e => { console.error('[FATAL] ' + e.message); process.exit(1); }); ''' def pwd(): r = subprocess.run(['sops','-d','D:/vault/clients/dataforth/ad2.sops.yaml'], capture_output=True, text=True, timeout=30, check=True) return yaml.safe_load(r.stdout)['credentials']['password'].replace('\\','') def ps(c, cmd, to=1800): enc = base64.b64encode(cmd.encode('utf-16-le')).decode() stdin, stdout, stderr = c.exec_command(f'powershell -NoProfile -EncodedCommand {enc}', timeout=to) return stdout.read().decode('utf-8','replace'), stderr.read().decode('utf-8','replace'), stdout.channel.recv_exit_status() c = paramiko.SSHClient() c.set_missing_host_key_policy(paramiko.AutoAddPolicy()) c.connect(HOST, username=USER, password=pwd(), timeout=30, banner_timeout=45, look_for_keys=False, allow_agent=False) try: print('=== STEP 1: restart testdatadb ===', flush=True) out, err, rc = ps(c, r'Restart-Service testdatadb -Force; Start-Sleep -Seconds 3; Get-Service testdatadb | Select Name,Status | Format-Table -AutoSize | Out-String', to=60) print(out, flush=True) print('=== STEP 2: deploy and run backfill node script ===', flush=True) sftp = c.open_sftp() remote_js = 'C:/Shares/testdatadb/_backfill_stragglers.js' with sftp.open(remote_js, 'w') as fh: fh.write(NODE_BACKFILL) sftp.close() out, err, rc = ps(c, r'cd C:\Shares\testdatadb; & node ./_backfill_stragglers.js') print(f'[rc={rc}]', flush=True) print(out, flush=True) if err.strip() and 'CLIXML' not in err: print('--- STDERR ---', flush=True) print(err[:2000], flush=True) sftp = c.open_sftp() try: sftp.remove(remote_js) except Exception: pass sftp.close() finally: c.close()