fix(clp-package)!: Restore zstd-compressed job configs#2375
Conversation
…ion-zstd # Conflicts: # components/log-ingestor/src/ingestion_job_manager/clp_ingestion.rs
WalkthroughThis PR switches compression job configuration storage and retrieval from Brotli-compressed MessagePack to Zstandard-compressed MessagePack across Rust, Python, and web UI components. It also updates dependencies, error handling, overflow handling, and validation tests. ChangesBrotli-to-Zstandard migration
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant LogIngestor
participant ZstdMsgpack
participant CompressionJobsTable
participant CompressionScheduler
participant WebUIServer
LogIngestor->>ZstdMsgpack: serialize(io_config)
ZstdMsgpack-->>LogIngestor: compressed job config bytes
LogIngestor->>CompressionJobsTable: insert compressed clp_config
CompressionScheduler->>CompressionJobsTable: load job_row.clp_config
CompressionScheduler->>ZstdMsgpack: deserialize compressed config
ZstdMsgpack-->>CompressionScheduler: ClpIoConfig
WebUIServer->>CompressionJobsTable: load compression metadata
WebUIServer->>WebUIServer: zstdDecompressSync and decode
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@components/clp-rust-utils/src/serde/zstd_msgpack.rs`:
- Around line 43-45: The zstd failure mapping in zstd_error currently only
formats the numeric result into Error::Zstd, which loses the real failure
reason. Update zstd_error to look up the human-readable zstd error name using
ZSTD_getErrorName and include that string in the Error::Zstd message, keeping
the existing Error::Zstd conversion path but replacing the generic "error code
{result}" text with the zstd-provided error name.
In
`@components/webui/packages/server/src/plugins/app/CompressionJobDbManager/index.ts`:
- Around line 1-26: The server package uses node:zlib zstd APIs in
CompressionJobDbManager, but no minimum Node version is declared for the
webui/server runtime. Add an engines.node floor of 22.15+ in either
components/webui/package.json or components/webui/packages/server/package.json
so the server cannot start on an unsupported Node version, and keep the change
aligned with the CompressionJobDbManager/index.ts usage of zstdCompressSync and
ZstdOptions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 736c0734-8064-4b12-91cf-fe1d4a3ed7db
⛔ Files ignored due to path filters (6)
Cargo.lockis excluded by!**/*.lockcomponents/clp-mcp-server/uv.lockis excluded by!**/*.lockcomponents/clp-package-utils/uv.lockis excluded by!**/*.lockcomponents/clp-py-utils/uv.lockis excluded by!**/*.lockcomponents/job-orchestration/uv.lockis excluded by!**/*.lockintegration-tests/uv.lockis excluded by!**/*.lock
📒 Files selected for processing (19)
components/api-server/src/error.rscomponents/clp-package-utils/clp_package_utils/scripts/native/compress.pycomponents/clp-package-utils/pyproject.tomlcomponents/clp-py-utils/clp_py_utils/zstd_msgpack.pycomponents/clp-py-utils/pyproject.tomlcomponents/clp-rust-utils/Cargo.tomlcomponents/clp-rust-utils/src/error.rscomponents/clp-rust-utils/src/serde.rscomponents/clp-rust-utils/src/serde/brotli_msgpack.rscomponents/clp-rust-utils/src/serde/zstd_msgpack.rscomponents/clp-rust-utils/tests/clp_config_test.rscomponents/job-orchestration/job_orchestration/scheduler/compress/compression_scheduler.pycomponents/job-orchestration/job_orchestration/scheduler/compress/partition.pycomponents/job-orchestration/pyproject.tomlcomponents/log-ingestor/src/ingestion_job_manager/clp_ingestion.rscomponents/webui/packages/server/src/plugins/app/CompressionJobDbManager/index.tscomponents/webui/packages/server/src/routes/api/compress-metadata/utils.tscomponents/webui/packages/server/src/test/compressMetadataUtils.test.tscomponents/webui/packages/server/src/test/compressionJobDbManager.test.ts
💤 Files with no reviewable changes (3)
- components/job-orchestration/pyproject.toml
- components/clp-package-utils/pyproject.toml
- components/clp-rust-utils/src/serde/brotli_msgpack.rs
| import { | ||
| constants as zlibConstants, | ||
| zstdCompressSync, | ||
| type ZstdOptions, | ||
| } from "node:zlib"; | ||
|
|
||
| import type {MySQLPromisePool} from "@fastify/mysql"; | ||
| import {encode} from "@msgpack/msgpack"; | ||
| import {ClpIoConfig} from "@webui/common/schemas/compression"; | ||
| import {FastifyInstance} from "fastify"; | ||
| import type {ClpIoConfig} from "@webui/common/schemas/compression"; | ||
| import type {FastifyInstance} from "fastify"; | ||
| import fp from "fastify-plugin"; | ||
| import {ResultSetHeader} from "mysql2"; | ||
| import type {ResultSetHeader} from "mysql2"; | ||
|
|
||
| import {publicSettings} from "../../../settings.js"; | ||
| import {COMPRESSION_JOBS_TABLE_COLUMN_NAMES} from "../../../typings/compression.js"; | ||
|
|
||
|
|
||
| const ZSTD_COMPRESSION_LEVEL = 3; | ||
|
|
||
| const ZSTD_COMPRESSION_OPTIONS: ZstdOptions = { | ||
| params: { | ||
| [zlibConstants.ZSTD_c_compressionLevel]: ZSTD_COMPRESSION_LEVEL, | ||
| }, | ||
| }; | ||
|
|
||
|
|
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check for Node.js version requirements in the webui server package and repo root.
fd -t f -H '(package\.json|\.nvmrc|\.node-version|Dockerfile)' components/webui . --max-depth 3 2>/dev/null | head -20
# Show engines field and any Node version pinning
rg -n --glob 'package.json' '"engines"|"node"' components/webui/packages/server/ . --max-depth 1 2>/dev/null | head -20
rg -n 'node' .nvmrc .node-version 2>/dev/nullRepository: y-scope/clp
Length of output: 349
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== package.json files =="
sed -n '1,220p' components/webui/package.json
echo
sed -n '1,220p' components/webui/packages/server/package.json
echo
sed -n '1,220p' components/webui/packages/client/package.json
echo
sed -n '1,220p' components/webui/packages/common/package.json
echo
echo "== version pin files =="
fd -H -t f '(^\.nvmrc$|^\.node-version$|^Dockerfile$|^package\.json$|^\.tool-versions$|^volta\.json$)' components/webui . 2>/dev/null | sort
echo
echo "== node version mentions =="
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' '\b(node\s*:?|\bnode\b|v22\.|v20\.|v18\.)' components/webui .github .gitlab-ci.yml azure-pipelines.yml 2>/dev/null | head -200Repository: y-scope/clp
Length of output: 22625
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== top-level and webui Node version declarations =="
fd -H -t f '(^\.nvmrc$|^\.node-version$|^\.tool-versions$|^package\.json$|^Dockerfile$|^docker-compose.*\.ya?ml$|^.*\.yml$|^.*\.yaml$|^.*\.json$)' . \
| rg '(^|/)(\.nvmrc|\.node-version|\.tool-versions|package\.json|Dockerfile|.*\.ya?ml|.*\.json)$' \
| head -300
echo
echo "== engines/node fields in likely config files =="
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' \
'"engines"\s*:|"\bnode\b"\s*:|node\s+[0-9]+\.[0-9]+\.[0-9]+|FROM\s+node:|runtime-?version|NODE_VERSION|engines:' \
.github components/webui components/core tools 2>/dev/null | head -300
echo
echo "== webui CI/workflow files =="
fd -H -t f '.github/workflows' . 2>/dev/null
rg -n --hidden --glob '.github/workflows/*' 'node|pnpm|setup-node|actions/setup-node|22\.|20\.' .github/workflows components/webui 2>/dev/null | head -300
echo
echo "== repo root package and version files =="
for f in package.json .nvmrc .node-version .tool-versions; do
if [ -f "$f" ]; then
echo "--- $f ---"
sed -n '1,220p' "$f"
fi
doneRepository: y-scope/clp
Length of output: 28450
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== workflow files =="
fd -H -t f .github/workflows . 2>/dev/null | sort
echo
echo "== node-related workflow lines =="
for f in $(fd -H -t f .github/workflows . 2>/dev/null); do
echo "--- $f ---"
rg -n 'setup-node|node-version|actions/setup-node|pnpm|22\.|20\.|18\.' "$f" || true
done
echo
echo "== root docs mentioning Node version =="
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' \
'\bNode\.?js\b|\bnode version\b|\bminimum Node\b|\bNode 22\b|\bNode 20\b' \
README* docs components/webui components .github 2>/dev/null | head -300Repository: y-scope/clp
Length of output: 170
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== github workflows and node pins =="
fd -H -t f '.github/workflows' . 2>/dev/null | sort | while read -r f; do
echo "--- $f ---"
sed -n '1,220p' "$f" | rg -n 'setup-node|node-version|node-version-file|pnpm|22\.|20\.|18\.' || true
done
echo
echo "== other repo-wide version pins =="
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' \
'setup-node|node-version-file|node-version:|volta|fnm|nvm|asdf|20\.19|22\.15|22\.19|22\.0' \
. 2>/dev/null | head -300Repository: y-scope/clp
Length of output: 186
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== search for explicit Node version pins in repo configs =="
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' \
'setup-node|node-version-file|node-version:|engines:|\"engines\"|\.nvmrc|\.node-version|\.tool-versions|NODE_VERSION|runtime-version|node22|Node 22|22\.15\.0|22\.19\.7' \
.github components/webui taskfile.yaml taskfiles tools 2>/dev/null | head -300
echo
echo "== .github files list =="
fd -H -t f . .github 2>/dev/null | sort | head -200
echo
echo "== webui taskfiles and package manifests containing node/version refs =="
for f in components/webui/package.json components/webui/packages/server/package.json components/webui/packages/server/tsconfig.json components/webui/pnpm-workspace.yaml components/webui/turbo.json taskfile.yaml; do
if [ -f "$f" ]; then
echo "--- $f ---"
sed -n '1,220p' "$f"
echo
fi
doneRepository: y-scope/clp
Length of output: 209
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== explicit Node pins and setup-node usages =="
rg -n --hidden --glob '!**/node_modules/**' --glob '!**/dist/**' --glob '!**/build/**' \
'actions/setup-node|setup-node|node-version|node-version-file|engines|\.nvmrc|\.node-version|\.tool-versions|NODE_VERSION|node22|22\.15\.0|22\.19\.7' \
.github components/webui taskfile.yaml taskfiles tools 2>/dev/null | head -300
echo
echo "== files under .github =="
find .github -maxdepth 3 -type f | sort | head -200Repository: y-scope/clp
Length of output: 22974
Add a Node 22.15+ engine floor for the server
node:zlib zstd APIs need Node 22.15+, but the webui manifests don’t declare a minimum engines.node version. Add one in components/webui/package.json or components/webui/packages/server/package.json so this service can’t be started on an unsupported runtime.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@components/webui/packages/server/src/plugins/app/CompressionJobDbManager/index.ts`
around lines 1 - 26, The server package uses node:zlib zstd APIs in
CompressionJobDbManager, but no minimum Node version is declared for the
webui/server runtime. Add an engines.node floor of 22.15+ in either
components/webui/package.json or components/webui/packages/server/package.json
so the server cannot start on an unsupported Node version, and keep the change
aligned with the CompressionJobDbManager/index.ts usage of zstdCompressSync and
ZstdOptions.
| aws-sdk-s3 = "1.121.0" | ||
| aws-sdk-sqs = "1.92.0" | ||
| brotli = "8.0.2" | ||
| libzstd-rs-sys = "0.0.1-prerelease.2" |
There was a problem hiding this comment.
reason choosing this over zstd-rs
the maintainer org of this libzstd-rs-sys seems much more reputable than https://github.com/gyscos/zstd-rs
…se-compression-zstd # Conflicts: # components/job-orchestration/job_orchestration/scheduler/compress/compression_scheduler.py
Description
Reverts the compression-job config payload format change from Brotli back to zstd across the CLP package job-submission path.
Breaking change
Warning
Existing package SQL databases may contain
compression_jobs.clp_configvalues written as Brotli-compressed MessagePack by older package builds. After this change, the WebUI decodes compression-job metadata as zstd-compressed MessagePack, so those historical compression-job rows must be migrated if operators need them to remain displayable in the Ingest page.This updates the native package compressor, job-orchestration schedulers, Rust log-ingestor submission path, and WebUI server submission/metadata decoding to write/read zstd-compressed MessagePack again. Rust zstd support uses
trifectatechfoundation/libzstd-rs-sys, with the unsafe FFI usage isolated in a small helper.The WebUI server path now stores zstd job configs directly through
CompressionJobDbManager.create(fastify), matching the pre-existing factory API. The API server was checked as well: it reads compression usage metadata but does not submitcompression_jobs.clp_config; the relevant Rust submitter is the log-ingestor, which is updated here.Migration
Pause compression-job submissions until the migration is complete.
Run these commands from a host that can reach the package SQL database, replacing the values below with its connection details:
Save the following as
migrate-compression-jobs.py:Then dump before upgrading and restore after starting the new package:
chmod +x migrate-compression-jobs.py ./migrate-compression-jobs.py dump # Upgrade and start the new package. ./migrate-compression-jobs.py restoreThis updates only
clp_config, preserving job IDs and metadata without truncatingcompression_jobs, which is referenced bycompression_tasks.query_jobs.job_configis raw MessagePack rather than Brotli/zstd-compressed MessagePack, so search-job rows do not need this codec migration.Checklist
Validation performed
task lint:fix-rusttask deps:lock:check-rusttask lint:check-rusttask lint:fix-jstasktask tests:rust-alltask tests:integration:clp-py-project-importspnpm --filter @webui/server testpnpm --filter @webui/server buildgit diff --check c6e14789f..HEADNo output, exit 0.
Package integration, JSON flavour:
Package integration, text flavour:
Package smoke start:
Package smoke compression:
Package smoke stop:
Legacy Brotli-to-zstd migration smoke:
Built and started the old package from
origin/main, then usedplaywright-cliagainsthttp://127.0.0.1:4000/ingestto submit one compression job and one search query through the WebUI server APIs:Dumped the old Brotli
compression_jobsrow with a one-offuvPython migration helper:Rebuilt and started the new zstd package, restored the dump as zstd, and verified the SQL payloads:
Reopened the new WebUI with
playwright-cli;/api/compress-metadatareturned 200 with the restoredmigration_brotlijob, the Ingest table displayed the restored succeeded row, andplaywright-cli consolereported:Summary by CodeRabbit
Improvements
Bug Fixes
Tests