Understanding and Troubleshooting Linux Ulimit Settings: A Deep Dive into Resource Limits and EAGAIN Errors


2 views

The EAGAIN error you encountered in your async code typically surfaces when a system call would block but the operation was requested in non-blocking mode. In your case:

{ [Error: spawn mediainfo EAGAIN]
  code: 'EAGAIN',
  errno: 'EAGAIN',
  syscall: 'spawn mediainfo',
  path: 'mediainfo',
  spawnargs: 
   [ '--Output=XML',
     '/home/buzut/testMedia' ],
  cmd: 'mediainfo --Output=XML /home/buzut/testMedia' }

This suggests your process hit a resource limitation during child process creation. The most likely culprits are process count (nproc) or memory constraints.

Let's break down the critical limits and their system impacts:

Process-Related Limits

  • nproc (-u): Max number of processes per user. Exceeding this causes fork() failures.
  • maxlogins: Limits concurrent user sessions.
  • priority (-e): Process scheduling priority (-20 to 19).

Memory Constraints

  • memlock (-l): Limits mlock() operations (critical for real-time apps).
  • as (-v): Total virtual memory address space.
  • rss: Physical memory usage limit.

File System Limitations

  • nofile (-n): Open file descriptors (affects databases/servers).
  • locks (-x): File locks (relevant for concurrent access).
  • fsize (-f): Maximum file creation size.

Your current limits show:

max user processes (-u) 127698
open files (-n) 64000

These seem generous, but let's verify actual usage:

# Check current process count
ps -u $(whoami) | wc -l

# Check open files
lsof -u $(whoami) | wc -l

Temporary Adjustment

# Increase process limit for current session
ulimit -u 200000

Permanent Configuration

Edit /etc/security/limits.conf:

buzut soft nproc 200000
buzut hard nproc 200000

Node.js Specific Fixes

For async process spawning:

const { spawn } = require('child_process');
const child = spawn('mediainfo', ['--Output=XML', filePath], {
  stdio: 'inherit',
  detached: true // Prevents EAGAIN in busy systems
});

Implement resource tracking in your app:

const fs = require('fs');
setInterval(() => {
  fs.readFile('/proc/${process.pid}/limits', (err, data) => {
    console.log('Current limits:', data.toString());
  });
}, 5000);
  1. Verify system-wide limits with cat /proc/sys/kernel/threads-max
  2. Check for cgroup restrictions (common in containers)
  3. Monitor dmesg for OOM killer activity
  4. Test with stripped-down process spawning

When dealing with async operations in Linux, you might encounter the frustrating EAGAIN error (Error Code 11), which indicates a temporary resource unavailability. This often stems from misconfigured ulimit settings that restrict process capabilities.

Let's examine the most impactful settings for async operations:

// Key parameters affecting async operations
nofile   - Maximum open files (default often too low for servers)
nproc    - Maximum processes per user (critical for Node.js clusters)
memlock  - Locked memory (affects some database operations)
msgqueue - POSIX message queues (important for IPC)
stack    - Thread stack size (can cause crashes if too small)

Your specific error suggests the system couldn't spawn a new process when executing mediainfo. This typically relates to either:

  • Reaching the user process limit (nproc)
  • Hitting the system-wide process limit
  • Insufficient memory allocation

Check current limits with:

// View current limits
$ ulimit -a

// Check system-wide limits
$ cat /proc/sys/kernel/threads-max
$ cat /proc/sys/kernel/pid_max
$ cat /proc/sys/vm/max_map_count

For Node.js applications handling many concurrent operations:

# /etc/security/limits.conf
* soft nofile 100000
* hard nofile 100000
* soft nproc 20000
* hard nproc 20000
* soft memlock unlimited
* hard memlock unlimited

# sysctl adjustments
vm.max_map_count=1048576
kernel.pid_max=4194304

Implement retry logic for robust operation:

const { spawn } = require('child_process');
const retry = require('async-retry');

async function runMediaInfo(file) {
  return await retry(
    async (bail) => {
      const proc = spawn('mediainfo', [
        '--Output=XML',
        file
      ]);
      
      // Handle process events and errors
      // ...
    },
    {
      retries: 3,
      minTimeout: 100
    }
  );
}

Regularly check resource usage:

# Count open files per process
$ lsof | wc -l

# Check process count per user
$ ps -u youruser | wc -l

# Monitor memory usage
$ free -h
$ cat /proc/meminfo

For containerized environments:

  • Docker: Use --ulimit flags
  • Kubernetes: Configure securityContext
  • Systemd: Set Limit* directives in service files