فهرست منبع

Merge pull request #26116 from overleaf/bg-history-redis-show-buffer

add script to display redis buffer for a given history ID

GitOrigin-RevId: 71c2e79480c0873d30801ed3c13aa9a7fc7873f6
Brian Gough 1 سال پیش
والد
کامیت
d280f40885
1فایلهای تغییر یافته به همراه117 افزوده شده و 0 حذف شده
  1. 117 0
      services/history-v1/storage/scripts/show_buffer.js

+ 117 - 0
services/history-v1/storage/scripts/show_buffer.js

@@ -0,0 +1,117 @@
+#!/usr/bin/env node
+// @ts-check
+
+const { rclientHistory: rclient } = require('../lib/redis')
+const { keySchema } = require('../lib/chunk_store/redis')
+const commandLineArgs = require('command-line-args')
+
+const optionDefinitions = [
+  { name: 'historyId', type: String, defaultOption: true },
+]
+
+// Column width for key display alignment; can be overridden with COL_WIDTH env variable
+const COLUMN_WIDTH = process.env.COL_WIDTH
+  ? parseInt(process.env.COL_WIDTH, 10)
+  : 45
+
+let options
+try {
+  options = commandLineArgs(optionDefinitions)
+} catch (e) {
+  console.error(
+    'Error parsing command line arguments:',
+    e instanceof Error ? e.message : String(e)
+  )
+  console.error('Usage: ./show_buffer.js <historyId>')
+  process.exit(1)
+}
+
+const { historyId } = options
+
+if (!historyId) {
+  console.error('Usage: ./show_buffer.js <historyId>')
+  process.exit(1)
+}
+
+function format(str, indent = COLUMN_WIDTH + 2) {
+  const lines = str.split('\n')
+  for (let i = 1; i < lines.length; i++) {
+    lines[i] = ' '.repeat(indent) + lines[i]
+  }
+  return lines.join('\n')
+}
+
+async function displayKeyValue(
+  rclient,
+  key,
+  { parseJson = false, formatDate = false } = {}
+) {
+  const value = await rclient.get(key)
+  let displayValue = '(nil)'
+  if (value) {
+    if (parseJson) {
+      try {
+        displayValue = format(JSON.stringify(JSON.parse(value), null, 2))
+      } catch (e) {
+        displayValue = `  Raw value: ${value}`
+      }
+    } else if (formatDate) {
+      const ts = parseInt(value, 10)
+      displayValue = `${new Date(ts).toISOString()} (${value})`
+    } else {
+      displayValue = value
+    }
+  }
+  console.log(`${key.padStart(COLUMN_WIDTH)}: ${displayValue}`)
+}
+
+async function displayBuffer(projectId) {
+  console.log(`Buffer for history ID: ${projectId}`)
+  console.log('--------------------------------------------------')
+
+  try {
+    const headKey = keySchema.head({ projectId })
+    const headVersionKey = keySchema.headVersion({ projectId })
+    const persistedVersionKey = keySchema.persistedVersion({ projectId })
+    const expireTimeKey = keySchema.expireTime({ projectId })
+    const persistTimeKey = keySchema.persistTime({ projectId })
+    const changesKey = keySchema.changes({ projectId })
+
+    await displayKeyValue(rclient, headKey, { parseJson: true })
+    await displayKeyValue(rclient, headVersionKey)
+    await displayKeyValue(rclient, persistedVersionKey)
+    await displayKeyValue(rclient, expireTimeKey, { formatDate: true })
+    await displayKeyValue(rclient, persistTimeKey, { formatDate: true })
+
+    const changesList = await rclient.lrange(changesKey, 0, -1)
+
+    // 6. changes
+    let changesListDisplay = '(nil)'
+    if (changesList) {
+      changesListDisplay = changesList.length
+        ? format(
+            changesList
+              .map((change, index) => `[${index}]: ${change}`)
+              .join('\n')
+          )
+        : '(empty list)'
+    }
+    console.log(`${changesKey.padStart(COLUMN_WIDTH)}: ${changesListDisplay}`)
+  } catch (error) {
+    console.error('Error fetching data from Redis:', error)
+    throw error
+  }
+}
+
+;(async () => {
+  let errorOccurred = false
+  try {
+    await displayBuffer(historyId)
+  } catch (error) {
+    errorOccurred = true
+  } finally {
+    rclient.quit(() => {
+      process.exit(errorOccurred ? 1 : 0)
+    })
+  }
+})()