Skip to content

feat(server): add server:optimize command with hardware-based PHP tuning - #78

Closed
loadinglucian wants to merge 1 commit into
mainfrom
feat/server-optimize-command
Closed

feat(server): add server:optimize command with hardware-based PHP tuning#78
loadinglucian wants to merge 1 commit into
mainfrom
feat/server-optimize-command

Conversation

@loadinglucian

@loadinglucian loadinglucian commented Nov 10, 2025

Copy link
Copy Markdown
Owner
  • Add hardware detection to server-info playbook (CPU cores, RAM, disk type)
  • Create server:optimize command that applies optimal PHP-FPM and OPcache settings
  • Add server-optimize playbook with intelligent process manager selection
  • Support dynamic/ondemand/static PM modes based on RAM availability
  • Include SSD optimizations and JIT compilation tuning

Summary by CodeRabbit

  • New Features
    • Added a new server optimization command that automatically configures PHP-FPM and OPcache settings based on server hardware specifications (CPU cores, RAM, disk type).
    • Enhanced server information display to include hardware configuration details (CPU cores, RAM, disk type).
    • Server hardware detection now runs automatically to gather CPU, memory, and storage specifications.

- Add hardware detection to server-info playbook (CPU cores, RAM, disk type)
- Create server:optimize command that applies optimal PHP-FPM and OPcache settings
- Add server-optimize playbook with intelligent process manager selection
- Support dynamic/ondemand/static PM modes based on RAM availability
- Include SSD optimizations and JIT compilation tuning
@coderabbitai

coderabbitai Bot commented Nov 10, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

The PR adds server hardware detection and optimization capabilities. It introduces a new server:optimize console command that detects server hardware specifications (CPU cores, RAM, disk type), prompts users for confirmation, and applies optimized PHP-FPM and OPcache configurations. The server-info playbook is enhanced with hardware detection functions, while a new server-optimize playbook implements the optimization logic.

Changes

Cohort / File(s) Summary
Console Command
app/Console/Server/ServerOptimizeCommand.php
New Symfony Console command implementing server:optimize. Displays a header, selects a server, retrieves and validates hardware info (CPU cores, RAM, disk type), prompts user confirmation, executes optimization playbook with environment variables, and displays applied PHP-FPM and OPcache settings on success.
Display Trait
app/Traits/ServersTrait.php
Extended displayServerInfo with conditional hardware details rendering. Formats and displays CPU cores, RAM (converting MB to GB), and disk type when hardware info is available.
Server Info Detection
playbooks/server-info.sh
Enhanced tool presence validation to require both ss and lsblk. Added three hardware detection functions: detect_cpu_cores(), detect_ram_mb(), detect_disk_type(). Integrated hardware detection into main workflow and outputs hardware metrics in YAML structure.
Server Optimization
playbooks/server-optimize.sh
New Bash playbook performing hardware-based PHP-FPM and OPcache optimization. Includes calculation functions for optimal settings based on RAM and CPU cores, configuration functions to apply settings, main execution flow that applies configurations, restarts PHP-FPM, and writes YAML summary output.

Sequence Diagram

sequenceDiagram
    actor User
    participant ServerOptimizeCommand as server:optimize<br/>Command
    participant ServersTrait as ServersTrait<br/>(getServerInfo)
    participant ServerInfoPlaybook as playbooks/<br/>server-info.sh
    participant OptimizePlaybook as playbooks/<br/>server-optimize.sh

    User->>ServerOptimizeCommand: Execute command
    ServerOptimizeCommand->>ServerOptimizeCommand: Display header & select server
    ServerOptimizeCommand->>ServersTrait: Get server info
    ServersTrait->>ServerInfoPlaybook: Execute playbook
    ServerInfoPlaybook->>ServerInfoPlaybook: Detect hardware<br/>(CPU, RAM, disk)
    ServerInfoPlaybook-->>ServersTrait: Return server info + hardware
    ServersTrait-->>ServerOptimizeCommand: Return validated info
    ServerOptimizeCommand->>User: Display hardware configuration
    ServerOptimizeCommand->>User: Prompt for optimization approval
    
    alt User Confirms
        ServerOptimizeCommand->>OptimizePlaybook: Execute with hardware env vars
        OptimizePlaybook->>OptimizePlaybook: Calculate PHP-FPM settings
        OptimizePlaybook->>OptimizePlaybook: Calculate OPcache settings
        OptimizePlaybook->>OptimizePlaybook: Apply configurations
        OptimizePlaybook->>OptimizePlaybook: Restart PHP-FPM
        OptimizePlaybook-->>ServerOptimizeCommand: Return results
        ServerOptimizeCommand->>User: Display success + applied settings
    else User Declines
        ServerOptimizeCommand->>User: Cancel gracefully
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • ServerOptimizeCommand.php: New command with error handling, environment variable management, and playbook orchestration logic
  • playbooks/server-optimize.sh: Most complex file—multiple calculation functions with parameter bounds, file modifications, permission handling, and structured output generation
  • playbooks/server-info.sh: Hardware detection functions with fallback logic and disk type heuristics require careful validation
  • Mixed file types (PHP and Bash) with distinct logic patterns across each file necessitate separate reasoning

Possibly related PRs

Poem

🐰 A rabbit hops through cores and RAM so bright,
Detecting disks and tuning PHP with might,
OPcache sings and FPM runs so fleet,
Hardware-optimized, the server's heartbeat!
Thump thump goes the code, hopping through the night ✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: adding a new server:optimize command with hardware-based PHP tuning, which directly corresponds to the new ServerOptimizeCommand class and related optimization playbook.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/server-optimize-command

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 11a9edb and 03ffd63.

📒 Files selected for processing (4)
  • app/Console/Server/ServerOptimizeCommand.php (1 hunks)
  • app/Traits/ServersTrait.php (1 hunks)
  • playbooks/server-info.sh (4 hunks)
  • playbooks/server-optimize.sh (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.php

📄 CodeRabbit inference engine (.cursor/rules/00-main.mdc)

**/*.php: Eliminate single-use methods: inline if a method is called only once
Cache computed values: initialize expensive calculations in the constructor
Avoid method call overhead: prefer direct property access when appropriate

Files:

  • app/Console/Server/ServerOptimizeCommand.php
  • app/Traits/ServersTrait.php
🧠 Learnings (1)
📚 Learning: 2025-09-22T11:10:21.459Z
Learnt from: CR
Repo: deployer-plus/deployer-php PR: 0
File: .cursor/rules/01-architecture.mdc:0-0
Timestamp: 2025-09-22T11:10:21.459Z
Learning: Applies to app/**/@(Service|Services)/**/*.php : Extract complex orchestration shared by multiple Commands into dedicated Services

Applied to files:

  • app/Console/Server/ServerOptimizeCommand.php
🧬 Code graph analysis (3)
playbooks/server-optimize.sh (1)
playbooks/server-info.sh (1)
  • run_cmd (127-133)
app/Traits/ServersTrait.php (1)
app/Services/IOService.php (3)
  • info (474-477)
  • displayDeets (543-566)
  • writeln (463-469)
playbooks/server-info.sh (3)
playbooks/server-optimize.sh (1)
  • run_cmd (35-41)
playbooks/demo-site.sh (1)
  • run_cmd (37-43)
playbooks/server-install.sh (1)
  • run_cmd (49-55)
🪛 Shellcheck (0.11.0)
playbooks/server-optimize.sh

[warning] 119-119: settings appears unused. Verify use (or export if used externally).

(SC2034)

🔇 Additional comments (9)
app/Traits/ServersTrait.php (1)

147-177: LGTM! Hardware information display is well-implemented.

The hardware detection and formatting logic is solid:

  • Defensive checks ensure the hardware array exists before processing
  • Type juggling between int/string is handled correctly
  • RAM conversion logic appropriately displays GB when >= 1, MB otherwise
  • Consistent formatting matches existing patterns in the codebase
app/Console/Server/ServerOptimizeCommand.php (1)

69-73: LGTM! Good error handling for missing hardware data.

The defensive check ensures hardware information is available before proceeding, with a clear error message guiding users to run server:install first.

playbooks/server-info.sh (4)

146-147: LGTM! Tool check correctly updated for new requirements.

Adding lsblk to the tool check is appropriate since the new detect_disk_type() function depends on it.


168-170: LGTM! CPU core detection is straightforward and reliable.

Using nproc with a sensible fallback is the standard approach for detecting CPU cores.


175-177: LGTM! RAM detection is correctly implemented.

The free -m command with awk parsing is standard and reliable for extracting total system RAM.


182-202: LGTM! Disk type detection is well-designed with appropriate fallbacks.

The two-tier detection strategy is solid:

  1. Primary: disc-gran (TRIM support) works reliably in virtualized/cloud environments
  2. Fallback: rotation flag works for physical disks

The regex pattern ^[sv]da correctly matches the first vda or sda device. While technically it could match "vdaa" or "sdaa", the predictable space-separated format of lsblk output makes this a non-issue in practice.

playbooks/server-optimize.sh (3)

50-70: LGTM! PHP-FPM calculation logic is sound.

The process manager selection strategy is well-designed:

  • ondemand for memory-constrained servers (< 1 GB)
  • static for high-memory servers (>= 8 GB)
  • dynamic for mid-range servers

The 40 MB average process size and 75% RAM allocation are reasonable defaults, with appropriate bounds checking (5-200 children).


75-99: LGTM! OPcache settings scale appropriately with available RAM.

The tiered configuration provides sensible defaults for different server sizes, with JIT buffer sizes that scale proportionally to OPcache memory.


205-230: LGTM! SSD-specific optimizations are well-implemented.

The conditional SSD optimizations are appropriate:

  • Creates a dedicated file cache directory
  • Sets correct ownership (www-data:www-data) and permissions (755)
  • Only enables file cache when SSD is detected

Comment on lines +62 to +98
$info = $this->getServerInfo($server);

if (is_int($info)) {
return $info;
}

// Extract hardware info
if (!isset($info['hardware']) || !is_array($info['hardware'])) {
$this->io->error('Server hardware information not available. Run server:install first.');

return Command::FAILURE;
}

$hardware = $info['hardware'];
$cpuCores = $hardware['cpu_cores'] ?? '1';
$ramMb = $hardware['ram_mb'] ?? '512';
$diskType = $hardware['disk_type'] ?? 'hdd';

/** @var string $cpuCores */
/** @var string $ramMb */
/** @var string $diskType */

$permissions = $info['permissions'] ?? 'none';
/** @var string $permissions */

//
// Display hardware summary
// ----

$this->io->writeln([
'',
'<fg=cyan>Hardware Configuration:</>',
" CPU Cores: <fg=yellow>{$cpuCores}</>",
" RAM: <fg=yellow>{$ramMb}MB</>",
" Disk: <fg=yellow>{$diskType}</>",
'',
]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove duplicate hardware display.

The hardware information is already displayed by getServerInfo() at line 62, which calls displayServerInfo() in ServersTrait. The second display at lines 91-98 shows the same information in a different format, creating redundant console output.

Apply this diff to remove the duplicate display:

     }
 
-    //
-    // Display hardware summary
-    // ----
-
-    $this->io->writeln([
-        '',
-        '<fg=cyan>Hardware Configuration:</>',
-        "  CPU Cores: <fg=yellow>{$cpuCores}</>",
-        "  RAM: <fg=yellow>{$ramMb}MB</>",
-        "  Disk: <fg=yellow>{$diskType}</>",
-        '',
-    ]);
-
     //
     // Confirm optimization
     // ----
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$info = $this->getServerInfo($server);
if (is_int($info)) {
return $info;
}
// Extract hardware info
if (!isset($info['hardware']) || !is_array($info['hardware'])) {
$this->io->error('Server hardware information not available. Run server:install first.');
return Command::FAILURE;
}
$hardware = $info['hardware'];
$cpuCores = $hardware['cpu_cores'] ?? '1';
$ramMb = $hardware['ram_mb'] ?? '512';
$diskType = $hardware['disk_type'] ?? 'hdd';
/** @var string $cpuCores */
/** @var string $ramMb */
/** @var string $diskType */
$permissions = $info['permissions'] ?? 'none';
/** @var string $permissions */
//
// Display hardware summary
// ----
$this->io->writeln([
'',
'<fg=cyan>Hardware Configuration:</>',
" CPU Cores: <fg=yellow>{$cpuCores}</>",
" RAM: <fg=yellow>{$ramMb}MB</>",
" Disk: <fg=yellow>{$diskType}</>",
'',
]);
$info = $this->getServerInfo($server);
if (is_int($info)) {
return $info;
}
// Extract hardware info
if (!isset($info['hardware']) || !is_array($info['hardware'])) {
$this->io->error('Server hardware information not available. Run server:install first.');
return Command::FAILURE;
}
$hardware = $info['hardware'];
$cpuCores = $hardware['cpu_cores'] ?? '1';
$ramMb = $hardware['ram_mb'] ?? '512';
$diskType = $hardware['disk_type'] ?? 'hdd';
/** @var string $cpuCores */
/** @var string $ramMb */
/** @var string $diskType */
$permissions = $info['permissions'] ?? 'none';
/** @var string $permissions */
//
// Confirm optimization
// ----
🤖 Prompt for AI Agents
In app/Console/Server/ServerOptimizeCommand.php around lines 62 to 98, the
hardware summary is being printed a second time (duplicate of displayServerInfo
invoked by getServerInfo()). Remove the redundant console output block that
writes the hardware summary (the $this->io->writeln([...]) section) so only the
original display from getServerInfo() remains; ensure any related empty lines or
comments are cleaned up to preserve formatting and return behavior.

Comment on lines +108 to +164
configure_php_fpm_pool() {
local ram_mb=$1
local pool_conf="/etc/php/8.4/fpm/pool.d/www.conf"

if ! run_cmd test -f "$pool_conf"; then
echo "Error: PHP-FPM pool config not found: $pool_conf" >&2
exit 1
fi

echo "✓ Configuring PHP-FPM process manager..."

local settings pm max_children param3 param4 param5
IFS='|' read -r pm max_children param3 param4 param5 <<< "$(calculate_php_fpm_settings "$ram_mb")"

# Apply process manager settings
if ! run_cmd sed -i "s/^pm = .*/pm = $pm/" "$pool_conf"; then
echo "Error: Failed to set pm mode" >&2
exit 1
fi

if ! run_cmd sed -i "s/^pm.max_children = .*/pm.max_children = $max_children/" "$pool_conf"; then
echo "Error: Failed to set pm.max_children" >&2
exit 1
fi

if [[ $pm == "ondemand" ]]; then
if ! run_cmd sed -i "s/^;*pm.process_idle_timeout = .*/pm.process_idle_timeout = $param3/" "$pool_conf"; then
echo "Error: Failed to set pm.process_idle_timeout" >&2
exit 1
fi
elif [[ $pm == "static" ]]; then
if ! run_cmd sed -i "s/^;*pm.start_servers = .*/pm.start_servers = $param3/" "$pool_conf"; then
echo "Error: Failed to set pm.start_servers" >&2
exit 1
fi
else # dynamic
if ! run_cmd sed -i "s/^pm.start_servers = .*/pm.start_servers = $param3/" "$pool_conf"; then
echo "Error: Failed to set pm.start_servers" >&2
exit 1
fi
if ! run_cmd sed -i "s/^pm.min_spare_servers = .*/pm.min_spare_servers = $param4/" "$pool_conf"; then
echo "Error: Failed to set pm.min_spare_servers" >&2
exit 1
fi
if ! run_cmd sed -i "s/^pm.max_spare_servers = .*/pm.max_spare_servers = $param5/" "$pool_conf"; then
echo "Error: Failed to set pm.max_spare_servers" >&2
exit 1
fi
fi

if ! run_cmd sed -i "s/^;*pm.max_requests = .*/pm.max_requests = 1000/" "$pool_conf"; then
echo "Error: Failed to set pm.max_requests" >&2
exit 1
fi

echo "pm=$pm|max_children=$max_children"
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Hardcoded PHP version limits flexibility.

The path /etc/php/8.4/fpm/pool.d/www.conf hardcodes PHP 8.4, which will break when the PHP version changes. This same issue appears on line 232.

Consider one of these approaches:

Option 1: Detect installed PHP version

configure_php_fpm_pool() {
	local ram_mb=$1
	local php_version
	php_version=$(php -r "echo PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION;")
	local pool_conf="/etc/php/${php_version}/fpm/pool.d/www.conf"
	
	if ! run_cmd test -f "$pool_conf"; then
		echo "Error: PHP-FPM pool config not found: $pool_conf" >&2
		exit 1
	fi
	# ... rest of function
}

Option 2: Pass PHP version as environment variable

configure_php_fpm_pool() {
	local ram_mb=$1
	local php_version=${DEPLOYER_PHP_VERSION:-8.4}
	local pool_conf="/etc/php/${php_version}/fpm/pool.d/www.conf"
	# ... rest of function
}
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 119-119: settings appears unused. Verify use (or export if used externally).

(SC2034)

🤖 Prompt for AI Agents
In playbooks/server-optimize.sh around lines 108 to 164 the PHP-FPM pool path is
hardcoded to /etc/php/8.4/fpm/pool.d/www.conf which will break for other PHP
versions; change the function to build pool_conf dynamically by obtaining the
installed PHP version (e.g., run php to read
PHP_MAJOR_VERSION.PHP_MINOR_VERSION) or use a DEPLOYER_PHP_VERSION environment
variable with a sensible default, assign
pool_conf="/etc/php/${php_version}/fpm/pool.d/www.conf", keep the existing
file-exists check and sed updates, and apply the same dynamic-path change for
the other hardcoded occurrence around line 232 so both places use the resolved
php_version with fallback and error handling.


echo "✓ Configuring PHP-FPM process manager..."

local settings pm max_children param3 param4 param5

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove unused variable declaration.

The settings variable is declared but never used. The actual parsing happens directly into separate variables on line 120.

Apply this diff:

-	local settings pm max_children param3 param4 param5
+	local pm max_children param3 param4 param5
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
local settings pm max_children param3 param4 param5
local pm max_children param3 param4 param5
🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 119-119: settings appears unused. Verify use (or export if used externally).

(SC2034)

🤖 Prompt for AI Agents
In playbooks/server-optimize.sh around line 119, the variable list declares an
unused `settings`; remove `settings` from the local declaration so only used
variables remain (e.g., change `local settings pm max_children param3 param4
param5` to `local pm max_children param3 param4 param5`) to eliminate the unused
variable warning and keep the declaration accurate.

Comment thread playbooks/server-optimize.sh
@loadinglucian
loadinglucian deleted the feat/server-optimize-command branch November 10, 2025 17:34
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.

1 participant