Skip to main content

Overview

The TailStack install scripts (install.ps1 and install.sh) are production-grade orchestration utilities that manage parallel PNPM installations across your entire monorepo. Unlike simple pnpm install -r, these scripts intelligently monitor system resources and dynamically adjust concurrency to prevent system crashes.

Key Features

Smart Parallelization

Dynamically adjusts concurrent installations based on real-time CPU and RAM usage

Load Monitoring

Continuously monitors system metrics to prevent resource exhaustion

Automatic Throttling

Suspends jobs when system load exceeds thresholds, resumes when safe

State Machine Architecture

Robust RUNNING/PAUSED state management with hysteresis loops

How It Works

System Architecture

The install script implements a sophisticated orchestration loop:

Three-State System

Active Processing Mode
  • Spawns new jobs based on available resources
  • Dynamic concurrency: Floor(Cores × (1 - CPU/100))
  • Minimum 1 job, maximum = logical cores
  • Monitors RAM: pauses if < 500MB free
Transitions:
  • → PAUSED when CPU or RAM exceeds 90%

Usage

# From repository root
.\scripts\install.ps1
Requirements:
  • PowerShell 5.1+ (Windows) or PowerShell Core 7+ (cross-platform)
  • PNPM installed and in PATH
  • Windows: CIM/WMI access for system monitoring

Load Monitoring System

Metrics Collection

The script monitors two critical metrics:

CPU Usage

Measurement:
  • Windows: Win32_Processor.LoadPercentage via CIM
  • Linux/macOS: /proc/stat delta calculation
Update Frequency: Every 1 second

RAM Usage

Measurement:
  • Windows: Win32_OperatingSystem memory counters
  • Linux: /proc/meminfo MemAvailable
  • macOS: vm_stat equivalent
Update Frequency: Every 1 second

Threshold System

Triggers: System enters PAUSED stateActions:
  1. All running jobs receive suspend signal
  2. No new jobs spawn
  3. Dashboard shows “PAUSED” status
Rationale: Prevents system from becoming unresponsive due to excessive load. Jobs are suspended (not killed) to preserve progress.
Triggers: System returns to RUNNING stateActions:
  1. All suspended jobs receive resume signal
  2. New jobs can spawn based on dynamic limits
  3. Dashboard shows “RUNNING” status
Rationale: Hysteresis (75% resume vs 90% pause) prevents rapid state oscillation.
Formula:
Remaining Capacity = 100 - Current CPU Usage
Dynamic Limit = Floor(Logical Cores × Remaining Capacity / 100)
Minimum Limit = 1
Example (8-core system):
  • CPU at 20% → 8 × 0.80 = 6 concurrent jobs
  • CPU at 50% → 8 × 0.50 = 4 concurrent jobs
  • CPU at 80% → 8 × 0.20 = 1 concurrent job

Output Examples

[36m---  PNPM ORCHESTRATOR ---[0m
Scanning for package.json...[32m Found 23 projects.[0m
-> Start: packages/api
-> Start: packages/web
-> Start: packages/mobile

[35m[PNPM Orchestrator (RUNNING)] CPU: 45% | RAM: 62% | Active: 3 | Queued: 20 | Progress: 13%[0m

[32m[Success] /home/user/project/packages/api[0m

-> Start: packages/shared

[35m[PNPM Orchestrator (RUNNING)] CPU: 52% | RAM: 68% | Active: 3 | Queued: 17 | Progress: 26%[0m

Advanced Features

Job Suspension (Process Control)

C# Interop with kernel32.dll
Native Thread Control
[DllImport("kernel32.dll")]
public static extern IntPtr OpenThread(int dwDesiredAccess, 
    bool bInheritHandle, int dwThreadId);

[DllImport("kernel32.dll")]
public static extern int SuspendThread(IntPtr hThread);

[DllImport("kernel32.dll")]
public static extern int ResumeThread(IntPtr hThread);
PowerShell Usage:
function Suspend-JobTree ($ProcessObject) {
    foreach ($thread in $ProcessObject.Threads) {
        $hThread = [ProcControl]::OpenThread(0x0002, $false, $thread.Id)
        [ProcControl]::SuspendThread($hThread) | Out-Null
        [ProcControl]::CloseHandle($hThread) | Out-Null
    }
}
Windows implementation suspends individual threads, preserving process state perfectly. Memory remains allocated but CPU consumption drops to zero.

Crash Prevention

Why standard pnpm install -r can crash your system:
  1. Spawns all installations simultaneously
  2. No resource monitoring
  3. Can exceed available RAM (OOM killer)
  4. Maxes out CPU (system becomes unresponsive)
  5. No graceful degradation
The TailStack install scripts solve these issues:
  • Dynamic concurrency based on actual load
  • Automatic throttling prevents resource exhaustion
  • Job suspension instead of termination
  • Progress preservation during pauses
  • Predictable behavior with state machine

Performance Characteristics

Typical Performance (vs sequential):
PackagesSequentialParallel ScriptSpeedup
5-102-5 min30-60 sec3-5×
10-305-15 min1-3 min4-6×
30-10015-45 min3-8 min5-7×
Factors affecting speed:
  • Network latency (package downloads)
  • Shared dependencies (PNPM store hits)
  • System specs (CPU cores, RAM, disk I/O)
  • Background load (other applications)
CPU Usage:
  • Startup: 20-40% (scanning phase)
  • Active: 60-90% (installation phase)
  • Throttled: 40-60% (dynamic adjustment)
  • PAUSED: 10-20% (monitoring only)
RAM Usage:
  • Per job: 100-300 MB average
  • Concurrent jobs: 1-3 GB total
  • Safety margin: 500 MB minimum free
  • Peak: Typically 60-80% of total RAM
System Requirements:
Monorepo SizeMin RAMMin CPURecommended
Small (5-10)4 GB2 cores8 GB, 4 cores
Medium (30)8 GB4 cores16 GB, 8 cores
Large (100+)16 GB8 cores32 GB, 16 cores
The script automatically adapts to available resources.

Troubleshooting

Check Summary Output:
[31mFailed:     3[0m
Common Causes:
  1. Network errors: Retry or check firewall
  2. Peer dependency conflicts: Check package.json
  3. Insufficient disk space: Clear PNPM store
  4. Corrupted cache: Run clean script first
Manual fix:
# Navigate to failed package
cd packages/failed-package

# Try installation with verbose logging
pnpm install --loglevel=debug
Symptoms:
  • Dashboard stops updating
  • Progress stuck at same percentage
  • System responsive but script unresponsive
Solutions:1. Interrupt gracefully (Bash):
# Press Ctrl+C
# Script kills all background jobs automatically
2. Force termination:
# PowerShell: Kill script process
Stop-Process -Name powershell -Force
# Bash: Kill script and children
pkill -f "install.sh"
Error Message:
pnpm is not found in PATH. Please install Node/PNPM first.
Solutions:Install PNPM globally:
npm install -g pnpm
Verify installation:
pnpm --version
Add to PATH (if needed):
# Add to ~/.bashrc or ~/.zshrc
export PATH="$HOME/.local/share/pnpm:$PATH"
Windows:
# Enable script execution
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
Linux/macOS:
# Make script executable
chmod +x ./scripts/install.sh

# Fix ownership if needed
sudo chown -R $USER:$USER .

Best Practices

1

Run After Clean

Always run clean script before install for best results:
./scripts/clean.sh
# Press 'y' to auto-launch install
2

Close Resource-Heavy Apps

Free up system resources before installation:
  • Close browsers with many tabs
  • Pause video streaming
  • Exit Docker containers
  • Stop development servers
3

Monitor First Run

Watch the dashboard during first run to understand system behavior:
  • Note typical CPU/RAM usage
  • Observe pause/resume cycles
  • Check completion time as baseline
4

Use in CI/CD Carefully

CI environments may need adjustments:
# GitHub Actions example
- name: Install dependencies
  run: ./scripts/install.sh
  timeout-minutes: 30
Consider using standard PNPM in CI (predictable resources):
- run: pnpm install --frozen-lockfile

Technical Implementation

State Machine Logic

State Transitions (Pseudo-code)
while (queue.length > 0 || running.length > 0) {
  metrics = getSystemMetrics();
  cleanupFinishedJobs();
  
  // Hysteresis: different thresholds for pause vs resume
  if (metrics.cpu >= 90 || metrics.ram >= 90) {
    if (state !== 'PAUSED') {
      suspendAllJobs();
      state = 'PAUSED';
    }
  } else if (metrics.cpu <= 75 && metrics.ram <= 75) {
    if (state === 'PAUSED') {
      resumeAllJobs();
      state = 'RUNNING';
    }
  }
  
  if (state === 'RUNNING') {
    dynamicLimit = calculateConcurrency(metrics, cores);
    spawnJobsUpToLimit(dynamicLimit);
  }
  
  updateDashboard(metrics, state);
  sleep(1000);
}

Metrics Collection

function Get-Metrics {
    $os = Get-CimInstance Win32_OperatingSystem
    $proc = Get-CimInstance Win32_Processor
    
    $totalRam = $os.TotalVisibleMemorySize  # KB
    $freeRam = $os.FreePhysicalMemory       # KB
    $ramUsage = 100 - [math]::Round(($freeRam / $totalRam) * 100)
    
    return @{
        CpuUsage  = [math]::Round($proc.LoadPercentage)
        RamUsage  = $ramUsage
        FreeRamMB = [math]::Round($freeRam / 1024)
    }
}

Clean Script

Learn about the cleanup utility that pairs with install

Custom Scripts

Create your own automation scripts for the monorepo

Monorepo Management

Understand PNPM workspaces and dependency management

Build docs developers (and LLMs) love