Skip to content

Commit d5a1ddd

Browse files
ThomasHickmantetron
authored andcommitted
Fix exec_js_process process caching (#701)
* Fix exec_js_process process caching The existing logic doesn't properly cache processes, leading to a new process being created for every invocation of `exec_js_process` (eventually leading to an error due to too many processes with many calls to execjs). This commit fixes this logic and adds tests for this.
1 parent f10d578 commit d5a1ddd

File tree

2 files changed

+34
-9
lines changed

2 files changed

+34
-9
lines changed

cwltool/sandboxjs.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,18 +142,27 @@ def exec_js_process(js_text, timeout=None, js_console=False, context=None, force
142142

143143
created_new_process = False
144144

145-
if (context is None and localdata.procs.get(js_engine) is None) \
146-
or (context is not None and localdata.procs.get((js_engine, context)) is None) \
147-
or localdata.procs[js_engine].poll() is not None \
145+
if context is None:
146+
nodejs = localdata.procs.get(js_engine)
147+
else:
148+
nodejs = localdata.procs.get((js_engine, context))
149+
150+
if nodejs is None \
151+
or nodejs.poll() is not None \
148152
or onWindows():
149153
res = resource_stream(__name__, js_engine)
150154
js_engine_code = res.read().decode('utf-8')
151155

152156
created_new_process = True
153157

154-
localdata.procs[js_engine] = new_js_proc(js_engine_code, force_docker_pull=force_docker_pull)
158+
new_proc = new_js_proc(js_engine_code, force_docker_pull=force_docker_pull)
155159

156-
nodejs = localdata.procs[js_engine]
160+
if context is None:
161+
localdata.procs[js_engine] = new_proc
162+
nodejs = new_proc
163+
else:
164+
localdata.procs[(js_engine, context)] = new_proc
165+
nodejs = new_proc
157166

158167
killed = []
159168

tests/test_js_sandbox.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,25 @@
22

33
import unittest
44

5-
from mock import Mock
5+
from mock import Mock, patch
6+
from mock import MagicMock
67

78
import cwltool
89
import cwltool.factory
910
# we should modify the subprocess imported from cwltool.sandboxjs
1011
from cwltool.sandboxjs import (check_js_threshold_version,
11-
subprocess)
12+
subprocess,
13+
exec_js_process)
14+
import cwltool.sandboxjs
15+
from cwltool.utils import onWindows
1216
from .util import get_data
17+
import pytest
1318

1419

1520
class Javascript_Sanity_Checks(unittest.TestCase):
1621

1722
def setUp(self):
18-
self.check_output = subprocess.check_output
23+
self.check_output = subprocess.check_output
1924

2025
def tearDown(self):
2126
subprocess.check_output = self.check_output
@@ -37,7 +42,7 @@ def test_node_version(self):
3742
self.assertEquals(check_js_threshold_version('node'), True)
3843

3944
def test_is_javascript_installed(self):
40-
pass
45+
pass
4146

4247

4348
class TestValueFrom(unittest.TestCase):
@@ -46,3 +51,14 @@ def test_value_from_two_concatenated_expressions(self):
4651
f = cwltool.factory.Factory()
4752
echo = f.make(get_data("tests/wf/vf-concat.cwl"))
4853
self.assertEqual(echo(), {u"out": u"a sting\n"})
54+
55+
56+
class ExecJsProcessTest(unittest.TestCase):
57+
@pytest.mark.skipif(onWindows(),
58+
reason="Caching processes for windows is not supported.")
59+
def test_caches_js_processes(self):
60+
exec_js_process("7", context="{}")
61+
62+
with patch("cwltool.sandboxjs.new_js_proc", new=Mock(wraps=cwltool.sandboxjs.new_js_proc)) as mock:
63+
exec_js_process("7", context="{}")
64+
mock.assert_not_called()

0 commit comments

Comments
 (0)