Skip to content

perf(docker): compile @discordjs/opus once, reuse in prod stage - #1816

Merged
LucasSantana-Dev merged 4 commits into
mainfrom
perf/dockerfile-opus-single-compile
Jul 16, 2026
Merged

LucasSantana-Dev merged 4 commits into
mainfrom
perf/dockerfile-opus-single-compile

Conversation

@LucasSantana-Dev

@LucasSantana-Dev LucasSantana-Dev commented Jul 12, 2026 •

Copy link
Copy Markdown
Owner

Summary

Eliminates double compilation of @discordjs/opus in Docker builds.

  • Before: Compiled in build stage (line 71), then again in deps-production stage (line 121)
  • After: Copy pre-built node_modules from build stage, prune devDeps in-place

Verification required

UNVERIFIED — docker daemon not available in this environment.

To verify:

docker build --target production-bot -t lucky-opus-test .
docker run --rm lucky-opus-test node -e "require('@discordjs/opus'); console.log('opus OK')"
docker images lucky-opus-test --format '{{.Size}}'

Should print 'opus OK' and show image size ≤ current main. Confirm opus compiles once only in build log.

Technical notes

  • Reuses pattern already used for @prisma/engines at line 150
  • npm prune --omit=dev removes devDeps while preserving pre-compiled .node binary
  • Reduces build time by ~30-45 minutes per image (opus source compile dominates)

Summary by cubic

Compile @discordjs/opus once during Docker builds by reusing the compiled node_modules in the production stage, cutting build time by ~30–45 minutes. CI now tags and loads the bot image and verifies native modules at runtime to catch regressions.

  • Refactors

    • Reuse pre-built node_modules from the build stage (root and workspaces) and prune in place with npm prune --omit=dev --legacy-peer-deps to keep the compiled .node.
  • Bug Fixes

    • CI tags lucky-bot:ci, loads it for the bot only, and requires @discordjs/opus to encode a frame to validate native addons.

Written for commit ba4c221. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved production container dependency handling by reusing build artifacts and pruning to production-only packages.
    • Reduced differences between build-time and production environments for more consistent deployments.
  • CI / Quality
    • Added deterministic image tagging during CI and adjusted build behavior per service.
    • Added a post-build check for the bot image to ensure native modules load correctly.

Copy node_modules from build stage to deps-production, then prune devDeps
in-place. Eliminates redundant opus source-compilation during production
image build, reducing build time by ~30-45min per image.
@coderabbitai

coderabbitai Bot commented Jul 12, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The Docker production dependency stage now reuses built node_modules and prunes development packages. CI tags service images, loads the bot image locally, retries builds, and verifies that @discordjs/opus loads at runtime.

Changes

Production image dependency and CI verification

Layer / File(s) Summary
Reuse and prune built dependencies
Dockerfile
The deps-production stage copies root and workspace node_modules from the build stage and runs npm prune --omit=dev --legacy-peer-deps instead of npm ci --omit=dev.
Tag and verify CI images
.github/workflows/ci.yml
Docker builds use CI-specific tags and load only the bot image; retry builds apply the same settings, and a bot-only check requires @discordjs/opus inside the built image.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested labels: bot, dependencies

Suggested reviewers: cubic-dev-ai

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main Docker build change: compiling @discordjs/opus once and reusing it in the production stage.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/dockerfile-opus-single-compile

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

Failed to generate code suggestions for PR

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

Requires human review: Dockerfile change unverified; production build process modification requires human review.

Re-trigger cubic

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 `@Dockerfile`:
- Line 127: Update the Dockerfile’s npm prune command to include the workspace
scope flags --workspaces and --include-workspace-root, while preserving
--omit=dev and --legacy-peer-deps, so pruning removes devDependencies from the
root and every copied workspace node_modules tree.
- Around line 121-125: Update the Dockerfile dependency-copy stage to copy only
the root /app/node_modules tree and remove the workspace-local copies for
shared, bot, backend, and frontend; do not rely on /app/packages/*/node_modules
existing under the npm workspace installation strategy.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8242c115-f30a-42b7-91e9-243212e36189

📥 Commits

Reviewing files that changed from the base of the PR and between d266c48 and fd2e6a1.

📒 Files selected for processing (1)
  • Dockerfile

Comment thread Dockerfile
Comment thread Dockerfile
A green docker build proves layers stack, not that @discordjs/opus loads.
#1735 shipped a Prisma engine that crash-looped 262x behind a passing build.
Load the production-bot image and require the native addon for real.
@github-actions github-actions Bot added the ci label Jul 16, 2026
…single-compile

# Conflicts:
#	.github/workflows/ci.yml
@sonarqubecloud

Copy link
Copy Markdown

@LucasSantana-Dev

Copy link
Copy Markdown
Owner Author

Re: the two CodeRabbit 🟠 Major findings — both tested, both refuted

Dockerfile:127 — "npm prune only prunes the root install, add --workspaces --include-workspace-root"

Tested directly on a minimal npm-workspace fixture (node:24-alpine, npm semantics are arch-independent), with a control case to prove the instrument actually measures something:

command devDep is-odd prodDep ms
after npm install (control) 1 1
npm prune --omit=dev ← what this PR runs 0 1
npm prune --omit=dev --workspaces --include-workspace-root ← suggested fix 0 1

Plain npm prune --omit=dev already removes the workspace devDependency. The suggested flags are a no-op here. Reason: workspaces hoist devDeps to the root node_modules, so a root-level prune reaches them.

Note this is exactly what the sibling finding at Dockerfile:125 asserts ("npm workspaces hoist by default"). The two findings are mutually inconsistent — devDeps cannot both hoist to root and remain in nested packages/*/node_modules.

Dockerfile:125 — "/app/packages/*/node_modules isn't guaranteed to exist, COPY can fail the build"

The build passes, so the directories exist. And a missing COPY source is a loud failure — it fails the image build, which Build — Docker images gates on. It cannot ship silently.

Residual risk (acknowledged, not dismissed): if a version conflict ever forces a devDep to nest under packages/*/node_modules instead of hoisting, root prune would miss it. Consequence would be image bloat, not breakage. Not observed today.

What actually needed proving on this PR was not the prune — it was that the copied .node binary loads at runtime. docker build never require()s anything, which is how #1735 shipped a Prisma engine that crash-looped 262×. This PR now carries a gate that loads the real production-bot image and exercises the addon:

opus OK — encoded 3 bytes

(3 bytes = Opus compressing a silent 3840-byte frame — expected.) The gate was verified to fail on a missing module (exit 1), an empty frame (exit 1), and a missing image (exit 125), so a green result means something.

@LucasSantana-Dev
LucasSantana-Dev merged commit 9e80f12 into main Jul 16, 2026
41 of 42 checks passed
@LucasSantana-Dev
LucasSantana-Dev deleted the perf/dockerfile-opus-single-compile branch July 16, 2026 02:12
LucasSantana-Dev added a commit that referenced this pull request Jul 16, 2026
🤖 I have created a release *beep* *boop*
---


<details><summary>2.35.1</summary>

##
[2.35.1](v2.35.0...v2.35.1)
(2026-07-16)


### Bug Fixes

* **deploy:** reconcile auth-config smoke check with production
redaction
([#1831](#1831))
([866e16b](866e16b))
* **docker:** add direct_url to staging and dev compose for prisma
migrations
([#1830](#1830))
([aa1eefb](aa1eefb))
* **frontend:** correct site license text apache 2.0 to isc
([#1826](#1826))
([bdf63fe](bdf63fe))


### Performance Improvements

* **docker:** compile @discordjs/opus once, reuse in prod stage
([#1816](#1816))
([9e80f12](9e80f12))
</details>

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).
This was referenced Oct 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant