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)
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 thepoll
system call, removing this limitation.
possible fix: use python 2.7+, or backport the code using poll
.
You can manually close the file descriptors. After calling communicate
, call proc.stderr.close()
and proc.stdout.close()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With