Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"filedescriptor out of range in select()" when using python's subprocess with rsync

the code below is used to sync uploaded picture to another place. it works, but after a period of time(about 10 days), the service is unusable , showing error: 'filedescriptor out of range in select()', but restart service solves the problem.

# sync.py

def sync_file(source_pic, hashval, retry_num=3):

    pic_path = os.path.join(gen_dir(hashval), os.path.split(source_pic)[1])
    filename = tempfile.mkstemp()[1]
    with open(filename, 'w') as f:
        f.write(pic_path)

    for sync_path in options.sync_paths:
        try_num = 0
        rsync_cmd = ['rsync','-au', '--files-from='+filename, options.pic_path, sync_path]

        while try_num < retry_num:
            proc = subprocess.Popen(rsync_cmd,stdout=subprocess.PIPE, stderr=subprocess.PIPE)
            stdout_value, stderr_value = proc.communicate()

            if len(stderr_value) != 0:
                logger.error('sync failed: %s' % stderr_value)
                try_num = try_num + 1
                #raise UploadException('sync failed')
            else:
                break

    os.remove(filename)

log info:

File "/path/to/sync.py", line 25, in sync_file
    stdout_value, stderr_value = proc.communicate()
File "/usr/lib/python2.6/subprocess.py", line 691, in communicate
    return self._communicate(input)
File "/usr/lib/python2.6/subprocess.py", line 1211, in _communicate
    rlist, wlist, xlist = select.select(read_set, write_set, [])
    ValueError: filedescriptor out of range in select()

are there unclosed file descriptors that cause the error? it seems subprocess doesn't close file descriptor, so when it runs 1024 times, the file descriptor is out of range. (we are using python 2.6, subprocess is forced to use select.select() which has a limit of 1024 file descriptors even epoll is available)

like image 351
limboy Avatar asked Oct 08 '11 08:10

limboy


2 Answers

https://bugzilla.redhat.com/show_bug.cgi?id=609020

Prior to Python 2.7, programs that used ulimit -n to enable communication with large numbers of subprocesses could still monitor only 1024 file descriptors at a time, which caused an exception:

ValueError: filedescriptor out of range in select()

This was due to the subprocess module using the select system call. The module now uses the poll system call, removing this limitation.

possible fix: use python 2.7+, or backport the code using poll.

like image 154
dnozay Avatar answered Oct 30 '22 00:10

dnozay


You can manually close the file descriptors. After calling communicate, call proc.stderr.close() and proc.stdout.close().

like image 45
David Schwartz Avatar answered Oct 30 '22 00:10

David Schwartz