Hi, Ryan.
<[email protected]> wrote on 2016-Jun-29 at 11:22 AM:
This is a Trac with Nginx and fcgi configuration on Debian 8.5, which has
always been problematic but has become very unstable over the past few days. I
searched existing issues (1), but am currently out of ideas. Excerpt from log
below, along with configuration.
Unfortunately I don't know Nginx or fcgi very well. I'm considering moving to
Apache with mod_wsgi. Any hints about what the problem might be would be
appreciated.
- Ryan
After [14419], we use PIPEs for stdin/stdout/stderr of Popen. I guess those
pipes leak and EMFILE is raised due to rendering many git revisions in tickets'
description in custom query. However, the pipes are closed by gc.collect() each
request.
Therefore, I think this issue wouldn't be solved by moving to mod_wsgi.
I attach patch which closes the pipes. Could you please try it?
--
Jun Omae <[email protected]> (大前 潤)
--
You received this message because you are subscribed to the Google Groups "Trac
Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/trac-users.
For more options, visit https://groups.google.com/d/optout.
diff --git a/tracopt/versioncontrol/git/PyGIT.py
b/tracopt/versioncontrol/git/PyGIT.py
index fc61319ed..0e482e19d 100644
--- a/tracopt/versioncontrol/git/PyGIT.py
+++ b/tracopt/versioncontrol/git/PyGIT.py
@@ -86,6 +86,13 @@ def _unquote(path):
return path
+def _close_proc_pipes(proc):
+ if proc:
+ for f in (proc.stdin, proc.stdout, proc.stderr):
+ if f:
+ f.close()
+
+
class GitCore(object):
"""Low-level wrapper around git executable"""
@@ -139,6 +146,7 @@ class GitCore(object):
p = self.__pipe(git_cmd, stdout=PIPE, stderr=PIPE, *cmd_args)
stdout_data, stderr_data = p.communicate()
+ _close_proc_pipes(p)
if self.__log and (p.returncode != 0 or stderr_data):
self.__log.debug('%s exits with %d, dir: %r, args: %s %r, '
'stderr: %r', self.__git_bin, p.returncode,
@@ -417,12 +425,15 @@ class Storage(object):
self.logger.debug("PyGIT.Storage instance for '%s' is constructed",
git_dir)
+ def _cleanup_proc(self, proc):
+ if proc:
+ _close_proc_pipes(proc)
+ terminate(proc)
+ proc.wait()
+
def __del__(self):
with self.__cat_file_pipe_lock:
- if self.__cat_file_pipe is not None:
- self.__cat_file_pipe.stdin.close()
- terminate(self.__cat_file_pipe)
- self.__cat_file_pipe.wait()
+ self._cleanup_proc(self.__cat_file_pipe)
#
# cache handling
@@ -683,9 +694,7 @@ class Storage(object):
# consistent state (Otherwise it happens that next time we
# call cat_file we get payload from previous call)
self.logger.debug("closing cat_file pipe")
- self.__cat_file_pipe.stdin.close()
- terminate(self.__cat_file_pipe)
- self.__cat_file_pipe.wait()
+ self._cleanup_proc(self.__cat_file_pipe)
self.__cat_file_pipe = None
def verifyrev(self, rev):
@@ -923,9 +932,8 @@ class Storage(object):
path, _ = path.rsplit('/', 1)
except ValueError:
break
- f.close()
- terminate(p[0])
- p[0].wait()
+ if p:
+ self._cleanup_proc(p[0])
p[:] = []
while True:
yield None
@@ -943,9 +951,7 @@ class Storage(object):
yield historian
finally:
if p:
- p[0].stdout.close()
- terminate(p[0])
- p[0].wait()
+ self._cleanup_proc(p[0])
def last_change(self, sha, path, historian=None):
if historian is not None:
diff --git a/tracopt/versioncontrol/git/tests/git_fs.py
b/tracopt/versioncontrol/git/tests/git_fs.py
index 500931f42..baf149f33 100644
--- a/tracopt/versioncontrol/git/tests/git_fs.py
+++ b/tracopt/versioncontrol/git/tests/git_fs.py
@@ -64,6 +64,7 @@ class GitCommandMixin(object):
def _git(self, *args, **kwargs):
proc = self._spawn_git(*args, **kwargs)
stdout, stderr = proc.communicate()
+ self._close_proc_pipes(proc)
self.assertEqual(0, proc.returncode,
'git exits with %r, args %r, kwargs %r, stdout %r, '
'stderr %r' %
@@ -75,6 +76,7 @@ class GitCommandMixin(object):
data = data.encode('utf-8')
proc = self._spawn_git('fast-import', stdin=PIPE)
stdout, stderr = proc.communicate(input=data)
+ self._close_proc_pipes(proc)
self.assertEqual(0, proc.returncode,
'git exits with %r, stdout %r, stderr %r' %
(proc.returncode, stdout, stderr))
@@ -96,6 +98,11 @@ class GitCommandMixin(object):
env['GIT_COMMITTER_DATE'] = dt
env['GIT_AUTHOR_DATE'] = dt
+ def _close_proc_pipes(self, proc):
+ for f in (proc.stdin, proc.stdout, proc.stderr):
+ if f:
+ f.close()
+
class BaseTestCase(unittest.TestCase, GitCommandMixin):