Skip to content

Commit 1188a91

Browse files
committed
Merge branch 'feature/subprocess-timeouts' into develop
[SVCS-683] Closes: #332
2 parents 42e5460 + 05408e9 commit 1188a91

File tree

5 files changed

+81
-41
lines changed

5 files changed

+81
-41
lines changed

mfr/extensions/jsc3d/export.py

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
import os
21
import shutil
3-
import subprocess
42
from http import HTTPStatus
3+
from subprocess import (DEVNULL,
4+
check_call,
5+
TimeoutExpired,
6+
CalledProcessError)
7+
from os.path import basename, splitext
58
from tempfile import NamedTemporaryFile
69

710
from mfr.core import exceptions
811
from mfr.core.extension import BaseExporter
9-
from mfr.extensions.jsc3d.settings import (FREECAD_BIN,
10-
FREECAD_CONVERT_SCRIPT)
12+
from mfr.extensions.jsc3d.settings import (TIMEOUT,
13+
FREECAD_BIN,
14+
CONVERSION_SCRIPT)
1115

1216

1317
class JSC3DExporter(BaseExporter):
@@ -22,16 +26,14 @@ def export(self):
2226
temp_source_file.name = self.source_file_path + '.step'
2327
shutil.copy2(self.source_file_path, temp_source_file.name)
2428

25-
subprocess.check_call([
26-
FREECAD_BIN,
27-
FREECAD_CONVERT_SCRIPT,
28-
temp_source_file.name,
29-
self.output_file_path,
30-
# silence output from freecadcmd
31-
], stdout=subprocess.DEVNULL)
29+
check_call(
30+
[FREECAD_BIN, CONVERSION_SCRIPT, temp_source_file.name, self.output_file_path],
31+
stdout=DEVNULL, # silence output from freecadcmd
32+
timeout=TIMEOUT,
33+
)
3234

33-
except subprocess.CalledProcessError as err:
34-
name, extension = os.path.splitext(os.path.split(self.source_file_path)[-1])
35+
except CalledProcessError as err:
36+
name, extension = splitext(basename(self.source_file_path))
3537
raise exceptions.SubprocessError(
3638
'Unable to export the file in the requested format, please try again later.',
3739
process='freecad',
@@ -42,3 +44,19 @@ def export(self):
4244
extension=extension or '',
4345
exporter_class='jsc3d',
4446
)
47+
48+
except TimeoutExpired as err:
49+
name, extension = splitext(basename(self.source_file_path))
50+
# The return code 52 is not the error code returned by the
51+
# subprocess, but the error given to it by this waterbutler
52+
# processs, for timing out.
53+
raise exceptions.SubprocessError(
54+
'JSC3D Conversion timed out.',
55+
code=HTTPStatus.GATEWAY_TIMEOUT,
56+
process='freecad',
57+
cmd=str(err.cmd),
58+
returncode=52,
59+
path=str(self.source_file_path),
60+
extension=extension or '',
61+
exporter_class='jsc3d'
62+
)

mfr/extensions/jsc3d/settings.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
config = settings.child('JSC3D_EXTENSION_CONFIG')
44

55
FREECAD_BIN = config.get('FREECAD_BIN', '/usr/bin/freecadcmd')
6-
FREECAD_CONVERT_SCRIPT = config.get('FREECAD_CONVERT_SCRIPT', '/code/mfr/extensions/jsc3d/freecad_converter.py')
6+
CONVERSION_SCRIPT = config.get('FREECAD_CONVERT_SCRIPT', '/code/mfr/extensions/jsc3d/freecad_converter.py')
7+
TIMEOUT = int(config.get('FREECAD_TIMEOUT', 30)) # In seconds
78
EXPORT_TYPE = config.get('EXPORT_TYPE', '.stl')
89
EXPORT_EXCLUSIONS = config.get('EXPORT_EXCLUSIONS', '.3ds .stl .obj .ctm').split(' ')

mfr/extensions/tabular/settings.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@
3737
})
3838

3939
PSPP_CONVERT_BIN = config.get('PSPP_CONVERT_BIN', '/usr/bin/pspp-convert')
40+
PSPP_CONVERT_TIMEOUT = int(config.get('PSPP_CONVERT_TIMEOUT', 30)) # In seconds

mfr/extensions/tabular/utilities.py

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import re
2-
import subprocess
2+
from http import HTTPStatus
3+
from subprocess import (check_call,
4+
TimeoutExpired,
5+
CalledProcessError)
36
from tempfile import NamedTemporaryFile
47

5-
from mfr.core import exceptions
6-
from mfr.extensions.tabular import compat, settings
8+
from mfr.extensions.tabular import compat
9+
from mfr.core.exceptions import SubprocessError
10+
from mfr.extensions.tabular.settings import (PSPP_CONVERT_BIN,
11+
PSPP_CONVERT_TIMEOUT)
712

813

914
def header_population(headers):
@@ -48,20 +53,33 @@ def sav_to_csv(fp):
4853
"""
4954
csv_file = NamedTemporaryFile(mode='w+b', suffix='.csv')
5055
try:
51-
subprocess.check_call([
52-
settings.PSPP_CONVERT_BIN,
53-
fp.name,
54-
csv_file.name,
55-
])
56-
except subprocess.CalledProcessError as err:
57-
raise exceptions.SubprocessError(
56+
check_call(
57+
[PSPP_CONVERT_BIN, fp.name, csv_file.name],
58+
timeout=PSPP_CONVERT_TIMEOUT,
59+
)
60+
except CalledProcessError as err:
61+
raise SubprocessError(
5862
'Unable to convert the SPSS file to CSV, please try again later.',
59-
code=500,
63+
code=HTTPStatus.INTERNAL_SERVER_ERROR,
6064
process='pspp',
6165
cmd=str(err.cmd),
6266
returncode=err.returncode,
6367
path=fp.name,
6468
extension='sav',
6569
exporter_class='tabular',
6670
)
71+
except TimeoutExpired as err:
72+
# The return code 52 is not the error code returned by the
73+
# subprocess, but the error given to it by this waterbutler
74+
# processs, for timing out.
75+
raise SubprocessError(
76+
'CSV Conversion timed out.',
77+
code=HTTPStatus.GATEWAY_TIMEOUT,
78+
process='pspp',
79+
cmd=str(err.cmd),
80+
returncode=52,
81+
path=fp.name,
82+
extension='sav',
83+
exporter_class='tabular'
84+
)
6785
return csv_file

mfr/extensions/unoconv/export.py

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,37 @@
1-
import os
2-
import subprocess
1+
from http import HTTPStatus
2+
from os.path import basename, splitext
3+
from subprocess import run, CalledProcessError
34

4-
from mfr.core import extension
5-
from mfr.core import exceptions
5+
from mfr.core.extension import BaseExporter
6+
from mfr.core.exceptions import SubprocessError
7+
from mfr.extensions.unoconv.settings import (PORT,
8+
ADDRESS,
9+
UNOCONV_BIN,
10+
UNOCONV_TIMEOUT)
611

7-
from mfr.extensions.unoconv import settings
812

9-
10-
class UnoconvExporter(extension.BaseExporter):
13+
class UnoconvExporter(BaseExporter):
1114

1215
def export(self):
1316
try:
14-
subprocess.run([
15-
settings.UNOCONV_BIN,
17+
run([
18+
UNOCONV_BIN,
1619
'-n',
17-
'-c', 'socket,host={},port={};urp;StarOffice.ComponentContext'.format(settings.ADDRESS, settings.PORT),
20+
'-c', 'socket,host={},port={};urp;StarOffice.ComponentContext'.format(ADDRESS, PORT),
1821
'-f', self.format,
1922
'-o', self.output_file_path,
2023
'-vvv',
2124
self.source_file_path
22-
], check=True, timeout=settings.UNOCONV_TIMEOUT)
23-
24-
except subprocess.CalledProcessError as err:
25-
name, extension = os.path.splitext(os.path.split(self.source_file_path)[-1])
26-
raise exceptions.SubprocessError(
25+
], check=True, timeout=UNOCONV_TIMEOUT)
26+
except CalledProcessError as err:
27+
name, extension = splitext(basename(self.source_file_path))
28+
raise SubprocessError(
2729
'Unable to export the file in the requested format, please try again later.',
2830
process='unoconv',
2931
cmd=str(err.cmd),
3032
returncode=err.returncode,
3133
path=str(self.source_file_path),
32-
code=400,
34+
code=HTTPStatus.BAD_REQUEST,
3335
extension=extension or '',
3436
exporter_class='unoconv',
3537
)

0 commit comments

Comments
 (0)