Skip to content

Optimize Docker build and improve configuration for Raspberry Pi#516

Open
ghempy53 wants to merge 120 commits intoalexemanuelol:masterfrom
ghempy53:claude/debug-hondabot-commands-1ZWte
Open

Optimize Docker build and improve configuration for Raspberry Pi#516
ghempy53 wants to merge 120 commits intoalexemanuelol:masterfrom
ghempy53:claude/debug-hondabot-commands-1ZWte

Conversation

@ghempy53
Copy link

@ghempy53 ghempy53 commented Feb 8, 2026

Summary

This PR significantly improves the Docker build process and configuration for Raspberry Pi 4 deployment. It includes a multi-stage Dockerfile optimized for ARM64 architecture, comprehensive documentation updates, and configuration fixes for environment variable parsing.

Key Changes

Docker & Build Optimization

  • Multi-stage Dockerfile: Implements a 4-stage build process (base → builder → deps → runtime) to reduce final image size and improve build caching
  • BuildKit support: Added syntax directive and cache mount optimizations for faster rebuilds on resource-constrained devices
  • ARM64 optimization: Uses node:22-bookworm-slim base image optimized for Raspberry Pi 4
  • Non-root user: Container now runs as unprivileged hondabot user for improved security
  • Health checks: Added proper health check configuration with appropriate timeouts for Pi 4

Configuration & Environment

  • .env.example: New template file with documented environment variables and memory recommendations for different Pi 4 models
  • .nvmrc: Added Node.js version pinning to v24
  • docker-compose.yml: Complete rewrite with:
    • Resource limits (1536m memory, 3.0 CPU) optimized for Pi 4 4GB model
    • DNS configuration to prevent resolution failures
    • Connection limits to prevent NAT table exhaustion
    • Tmpfs for temp files to reduce SD card wear
    • Proper logging configuration with rotation
    • Network isolation and security options

Code Fixes

  • config/index.js: Fixed environment variable parsing:
    • Parse numeric values as integers instead of strings
    • Properly parse boolean values (only true if explicitly 'true')
    • Fixed default value handling for needAdminPrivileges

Documentation

  • README.md: Completely rewritten with:
    • Clear installation instructions for Raspberry Pi
    • Docker helper script command reference
    • Resource configuration table for different Pi models
    • Troubleshooting section with common issues and solutions
    • Complete command reference for Discord slash commands and in-game commands
    • Backup and update procedures

File Management

  • .dockerignore: Expanded with comprehensive exclusions (113 lines) to optimize build context
  • .gitignore: Added .DS_Store entries and dist/ directory

Notable Implementation Details

  • BuildKit cache mounts: Dramatically speeds up npm install on subsequent builds by caching downloaded packages
  • Memory optimization: Pre-compiles TypeScript to JavaScript for faster startup and lower runtime memory usage
  • Volume strategy: Separates persistent data (credentials, instances, logs, maps) from temporary files
  • Graceful shutdown: Uses dumb-init as entrypoint to properly handle signals
  • Logging: JSON-file driver with compression and rotation to prevent disk space issues on Pi

Testing Recommendations

  • Build on Raspberry Pi 4 with different RAM configurations (1GB, 2GB, 4GB, 8GB)
  • Verify container starts and health checks pass
  • Test volume persistence across container restarts
  • Validate environment variable parsing with various input formats

https://claude.ai/code/session_0194xa2bxYhJQ5QGuR7Za3Mi

claude and others added 30 commits February 6, 2026 06:58
The builder stage had the same issue as deps - the postinstall script
needs patches/rustplus.proto but only package.json was copied before
npm ci. Also upgrades npm from 11.6.2 to 11.9.0 in the base stage.

https://claude.ai/code/session_011a43nDEyNcw7vcRTmTvvUT
…shes-WcnkM

Fix builder stage missing patches/ dir, upgrade npm to 11.9.0
Node 24.13.0's built-in undici causes "SocketError: other side closed"
on all Discord REST API calls. The Gateway WebSocket works fine but
message sends fail every ~15 seconds. Node 22 is the current LTS
release and matches the package.json engines requirement (>=22.0.0).

https://claude.ai/code/session_011a43nDEyNcw7vcRTmTvvUT
…ashes-WcnkM

Downgrade Docker image from Node 24 to Node 22 (LTS)
- Change SellOrder.amountInStock from required to optional in proto
  definition to prevent ProtocolError crash when Rust servers omit
  this field from vending machine data
- Default amountInStock to 0 when missing in vendingMachineHandler
  and market command to avoid undefined values
- Add consecutive log deduplication to Logger to collapse repeated
  identical messages into a single "... repeated N more times" line

https://claude.ai/code/session_01S7t3innQDX5bivr6qNpC1R
Fix SellOrder decode crash and reduce log spam
The Rust+ server stopped sending the isOnline field in
AppTeamInfo.Member broadcasts, causing a ProtocolError crash
on decode. Changed isOnline from required to optional in the
proto definition and added a fallback default of false in Player.js.

https://claude.ai/code/session_017LMsEHYaVmSTfRWGTL3Gpw
Fix Member decode crash: make isOnline optional in proto
The Rust+ server is also omitting the 'type' field from
AppTeamInfo.Note, causing the same class of ProtocolError crash.
Made all Note fields optional to match current server behavior.

https://claude.ai/code/session_017LMsEHYaVmSTfRWGTL3Gpw
…field

The Rust+ server keeps dropping required proto fields (isOnline, type,
etc.), causing uncaught ProtocolError exceptions that crash the bot.
Rather than patching individual fields one at a time, wrap the entire
websocket message decode in a try/catch and emit the error through the
existing error event handler. This prevents ALL future proto decode
crashes.

- Created patches/rustplus.js with try/catch around AppMessage.decode()
- Updated postinstall to copy both proto and js patches

https://claude.ai/code/session_017LMsEHYaVmSTfRWGTL3Gpw
sendMessage() returns undefined when a Discord channel doesn't exist
or a message send/edit fails. 11 call sites accessed message.id
without checking for this, causing TypeError crashes. Added null
checks before accessing message.id in all affected functions.

https://claude.ai/code/session_017LMsEHYaVmSTfRWGTL3Gpw
Fix crash when sendMessage returns undefined
When the saved category ID was null or stale, the bot created a new
rustplusplus category without checking if one already existed by name.
Now it falls back to getCategoryByName before creating a new one.

https://claude.ai/code/session_017LMsEHYaVmSTfRWGTL3Gpw
The Rust+ server stopped sending queuedPlayers in AppInfo responses,
causing getInfo to fail. This cascaded: polling returned early, team
was never initialized, and updateLeaderRustPlusLiteInstance crashed
accessing leaderSteamId on null.

- Made AppInfo.queuedPlayers optional in proto
- Added null guard for this.team in updateLeaderRustPlusLiteInstance

https://claude.ai/code/session_017LMsEHYaVmSTfRWGTL3Gpw
Fix AppInfo.queuedPlayers decode crash and null team guard
Downgrade @types/node from 24 to 22 to match runtime
Change default in-game trademark from rustplusplus to HondaBot
When the saved channel ID was null or stale, the bot created new
channels without checking if they already existed under the HondaBot
category. Now searches by name within the parent category before
creating, matching the same fix applied to SetupGuildCategory.

https://claude.ai/code/session_017LMsEHYaVmSTfRWGTL3Gpw
The trademark change to HondaBot only applied to new instances since
the instance loader preserves existing values. Added a migration step
to convert the old 'rustplusplus' trademark to 'HondaBot' on load.

The time distance threshold (> 1 hour) was too tight for servers with
faster time scales, causing repeated error spam and resetting time
tracking on every poll. Increased to > 4 hours to still detect actual
skip-night events (8+ hour jumps) while allowing normal progression.

https://claude.ai/code/session_017LMsEHYaVmSTfRWGTL3Gpw
Reuse existing channels in category instead of creating duplicates
- Fix interactionCreate.js: isCommand was referenced as a property instead
  of called as a method (isCommand vs isCommand()), causing the invalid
  channel check to never trigger. Also add missing return statement to
  prevent double-processing of interactions from invalid channels.

- Replace deprecated ephemeral option with flags API across all 21 command
  files, discordEmbeds.js, and discordMessages.js. Discord.js v14.25.1
  deprecated the ephemeral property in favor of
  flags: [Discord.MessageFlags.Ephemeral].

- Remove undici v7.x override from package.json. The override forced an
  incompatible major version of undici that caused SocketError: other side
  closed errors during HTTP requests to Discord's API, which was the
  primary cause of /reset settings failing (SetupSettingsMenu sends ~20
  messages to rebuild the settings channel, and SocketErrors caused those
  sends to fail silently).

https://claude.ai/code/session_01TUY2uZwzjNuN3yHtvvTbT8
…-qzrBn

Fix Discord reset command and resolve SocketErrors
Fix 31 instances of un-awaited async Discord.js calls:
- 14 interaction.deferUpdate() in buttonHandler.js
- 13 interaction.deferUpdate() in modalHandler.js
- 2 interaction.deferUpdate() in interactionCreate.js
- 1 client.interactionReply() in reset.js
- 1 client.interactionReply() in role.js

Without await, these async operations run as fire-and-forget,
causing race conditions and preventing try/catch blocks from
catching errors from the Discord API.

https://claude.ai/code/session_01TUY2uZwzjNuN3yHtvvTbT8
…-qzrBn

Add missing await on async Discord interaction methods
…te limiting

- Fix TypeError on getCommandTime by adding null guards for time/team/info/mapMarkers
  across all getCommand* methods in RustPlus.js and the inGameCommandHandler dispatcher
- Change spawnTime, isAlive, deathTime from required to optional in rustplus.proto to
  prevent ProtocolError when Rust+ server omits these fields
- Add nullish coalescing defaults in Player.js for the now-optional proto fields
- Add Timer.sleep(1100) rate limiting in SetupSettingsMenu.js, SetupSwitchGroups.js,
  SetupServerList.js, and SetupTrackers.js to stay within Discord's 5msg/5s limit
- Add null guards in pollingHandler, timeHandler, teamHandler, and message.js event
  handlers to prevent crashes during the initialization race window

https://claude.ai/code/session_0194xa2bxYhJQ5QGuR7Za3Mi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants