Skip to content

Commit bb3e9cf

Browse files
authored
Merge pull request #49 from Normal-OJ/fix-mem-usage
fix: high mem usage issue
2 parents 38aec36 + 5cbd9da commit bb3e9cf

3 files changed

Lines changed: 43 additions & 43 deletions

File tree

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM python:alpine
1+
FROM python:3.13-alpine
22

33
WORKDIR /app
44

dispatcher/dispatcher.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
import requests
66
import pathlib
77
import queue
8-
import textwrap
98
import shutil
9+
import tempfile
1010
from datetime import datetime
1111

1212
from runner.submission import SubmissionRunner
@@ -293,11 +293,6 @@ def create_container(
293293
finally:
294294
self.dec_container()
295295
logger().info(f'finish task {submission_id}/{case_no}')
296-
# truncate long stdout/stderr
297-
_res = res.copy()
298-
for k in ('Stdout', 'Stderr'):
299-
_res[k] = textwrap.shorten(_res.get(k, ''), 37, placeholder='...')
300-
logger().debug(f'runner result: {_res}')
301296
with self.locks[submission_id]:
302297
self.on_case_complete(
303298
submission_id=submission_id,
@@ -378,16 +373,26 @@ def on_submission_complete(self, submission_id: str):
378373
assert [*submission_result.keys()] == [*range(len(submission_result))]
379374
submission_result = [*submission_result.values()]
380375
# post data
381-
submission_data = {
382-
'tasks': submission_result,
383-
'token': config.SANDBOX_TOKEN
384-
}
385-
self.release(submission_id)
386-
logger().info(f'send to BE [submission_id={submission_id}]')
387-
resp = requests.put(
388-
f'{config.BACKEND_API}/submission/{submission_id}/complete',
389-
json=submission_data,
390-
)
376+
with tempfile.NamedTemporaryFile("w") as tmpf:
377+
submission_data = {
378+
'tasks': submission_result,
379+
'token': config.SANDBOX_TOKEN
380+
}
381+
# write payload to file
382+
json.dump(submission_data, tmpf)
383+
tmpf.flush()
384+
# release resources
385+
del submission_data
386+
self.release(submission_id)
387+
388+
logger().info(f'send to BE [submission_id={submission_id}]')
389+
# open in binary mode as requests needs a binary stream
390+
with open(tmpf.name, "rb") as payload:
391+
resp = requests.put(
392+
f'{config.BACKEND_API}/submission/{submission_id}/complete',
393+
data=payload,
394+
headers={'Content-Type': 'application/json'},
395+
)
391396
logger().debug(f'get BE response: [{resp.status_code}] {resp.text}', )
392397
# clear
393398
if resp.ok:

runner/sandbox.py

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import tarfile
44
import tempfile
55
from dataclasses import dataclass
6-
from io import BytesIO
76
from typing import Optional
7+
from pathlib import Path
88
import docker
99

1010

@@ -115,21 +115,11 @@ def run(self):
115115
raise JudgeError
116116
# retrive result
117117
try:
118-
result = self.get(
119-
container=container,
120-
path='/result/',
121-
filename='result',
122-
).split('\n')
123-
stdout = self.get(
124-
container=container,
125-
path='/result/',
126-
filename='stdout',
127-
)
128-
stderr = self.get(
129-
container=container,
130-
path='/result/',
131-
filename='stderr',
118+
result, stdout, stderr = self.get_result(
119+
container,
120+
['result', 'stdout', 'stderr'],
132121
)
122+
result = result.split('\n')
133123
except Exception as e:
134124
self.client.remove_container(container, v=True, force=True)
135125
logging.error(e)
@@ -147,16 +137,21 @@ def run(self):
147137
DockerExitCode=exit_status['StatusCode'],
148138
)
149139

150-
def get(self, container, path, filename):
151-
bits, _ = self.client.get_archive(container, f'{path}{filename}')
152-
tarbits = b''.join(bits)
153-
tar = tarfile.open(fileobj=BytesIO(tarbits))
154-
with tempfile.TemporaryDirectory() as extract_path:
155-
tar.extract(filename, extract_path)
156-
with open(
157-
f'{extract_path}/{filename}',
140+
def get_result(self, container, filenames: list[str]) -> list[str]:
141+
result_dir = '/result'
142+
bits, _ = self.client.get_archive(container, result_dir)
143+
with (tempfile.NamedTemporaryFile() as
144+
tarball, tempfile.TemporaryDirectory() as extract_path):
145+
for chunk in bits:
146+
tarball.write(chunk)
147+
tarball.flush()
148+
tarball.seek(0)
149+
with tarfile.open(fileobj=tarball) as tar:
150+
tar.extractall(extract_path)
151+
return [
152+
open(
153+
Path(extract_path) / result_dir.lstrip('/') / filename,
158154
'r',
159155
errors='ignore',
160-
) as f:
161-
contents = f.read()
162-
return contents
156+
).read() for filename in filenames
157+
]

0 commit comments

Comments
 (0)