rpc 通信和判题初步测试通过;判题服务器不再依赖 redis 和 mysql。

This commit is contained in:
virusdefender 2015-11-29 21:29:26 +08:00
parent 236102b6ac
commit 3311a4c899
15 changed files with 96 additions and 42 deletions

View File

@ -7,7 +7,7 @@ from problem.models import AbstractProblem
from group.models import Group from group.models import Group
from utils.models import RichTextField from utils.models import RichTextField
from jsonfield import JSONField from jsonfield import JSONField
from judge.judger.result import result from judge.result import result
GROUP_CONTEST = 0 GROUP_CONTEST = 0

View File

@ -7,16 +7,16 @@ languages = {
"src_name": "main.c", "src_name": "main.c",
"code": 1, "code": 1,
"syscalls": "!execve:k,flock:k,ptrace:k,sync:k,fdatasync:k,fsync:k,msync,sync_file_range:k,syncfs:k,unshare:k,setns:k,clone:k,query_module:k,sysinfo:k,syslog:k,sysfs:k", "syscalls": "!execve:k,flock:k,ptrace:k,sync:k,fdatasync:k,fsync:k,msync,sync_file_range:k,syncfs:k,unshare:k,setns:k,clone:k,query_module:k,sysinfo:k,syslog:k,sysfs:k",
"compile_command": "gcc -DONLINE_JUDGE -O2 -w -std=c99 {src_path} -lm -o {exe_path}main", "compile_command": "gcc -DONLINE_JUDGE -O2 -w -std=c99 {src_path} -lm -o {exe_path}/main",
"execute_command": "{exe_path}main" "execute_command": "{exe_path}/main"
}, },
2: { 2: {
"name": "cpp", "name": "cpp",
"src_name": "main.cpp", "src_name": "main.cpp",
"code": 2, "code": 2,
"syscalls": "!execve:k,flock:k,ptrace:k,sync:k,fdatasync:k,fsync:k,msync,sync_file_range:k,syncfs:k,unshare:k,setns:k,clone:k,query_module:k,sysinfo:k,syslog:k,sysfs:k", "syscalls": "!execve:k,flock:k,ptrace:k,sync:k,fdatasync:k,fsync:k,msync,sync_file_range:k,syncfs:k,unshare:k,setns:k,clone:k,query_module:k,sysinfo:k,syslog:k,sysfs:k",
"compile_command": "g++ -DONLINE_JUDGE -O2 -w -std=c++11 {src_path} -lm -o {exe_path}main", "compile_command": "g++ -DONLINE_JUDGE -O2 -w -std=c++11 {src_path} -lm -o {exe_path}/main",
"execute_command": "{exe_path}main" "execute_command": "{exe_path}/main"
}, },
3: { 3: {
"name": "java", "name": "java",

View File

@ -21,6 +21,7 @@ class JudgeInstanceRunner(object):
try: try:
os.mkdir(judge_base_path) os.mkdir(judge_base_path)
os.chmod(judge_base_path, 0777)
# 将代码写入文件 # 将代码写入文件
src_path = os.path.join(judge_base_path, language["src_name"]) src_path = os.path.join(judge_base_path, language["src_name"])

View File

@ -1,16 +0,0 @@
# coding=utf-8
import socket
import redis
from .rpc_client import TimeoutServerProxy
from .settings import redis_config
from .models import JudgeServer
class JudgeDispatcher(object):
def __init__(self):
self.redis = redis.StrictRedis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"])
def judge(self):
pass

View File

@ -3,7 +3,7 @@ from django.db import models
class JudgeServer(models.Model): class JudgeServer(models.Model):
ip = models.IPAddressField() ip = models.GenericIPAddressField()
port = models.IntegerField() port = models.IntegerField()
# 这个服务器最大可能运行的判题实例数量 # 这个服务器最大可能运行的判题实例数量
max_instance_number = models.IntegerField() max_instance_number = models.IntegerField()

View File

@ -1,9 +0,0 @@
# coding=utf-8
import os
redis_config = {
"host": os.environ.get("REDIS_PORT_6379_TCP_ADDR"),
"port": 6379,
"db": 0
}

34
judge_dispatcher/tasks.py Normal file
View File

@ -0,0 +1,34 @@
# coding=utf-8
import json
from celery import shared_task
from rpc_client import TimeoutServerProxy
from judge.result import result
from submission.models import Submission
@shared_task
def create_judge_task(submission_id, code, language_code, time_limit, memory_limit, test_case_id):
submission = Submission.objects.get(id=submission_id)
try:
s = TimeoutServerProxy('http://121.42.198.156:8080', timeout=20)
data = s.run(submission_id, language_code, code, time_limit, memory_limit, test_case_id)
print data
# 编译错误
if data["code"] == 1:
submission.result = result["compile_error"]
submission.info = data["data"]["error"]
# system error
elif data["code"] == 2:
submission.result = result["system_error"]
submission.info = data["data"]["error"]
elif data["code"] == 0:
submission.result = data["data"]["result"]
submission.info = json.dumps(data["data"]["info"])
submission.accepted_answer_time = data["data"]["accepted_answer_time"]
except Exception as e:
submission.result = result["system_error"]
submission.info = str(e)
finally:
submission.save()

View File

@ -2,15 +2,15 @@
import redis import redis
import datetime import datetime
from rest_framework.views import APIView from rest_framework.views import APIView
from judge.judger.result import result from judge.result import result
from judge.judger_controller.settings import redis_config from django.conf import settings
from utils.shortcuts import success_response from utils.shortcuts import success_response
from submission.models import Submission from submission.models import Submission
class QueueLengthMonitorAPIView(APIView): class QueueLengthMonitorAPIView(APIView):
def get(self, request): def get(self, request):
r = redis.Redis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"]) r = redis.Redis(host=settings.redis_config["host"], port=settings.redis_config["port"], db=settings.redis_config["db"])
waiting_number = r.get("judge_queue_length") waiting_number = r.get("judge_queue_length")
if waiting_number is None: if waiting_number is None:
waiting_number = 0 waiting_number = 0

View File

@ -6,4 +6,9 @@
\___/ |_| |_||_||_||_| |_| \___| \___/ \__,_| \__,_| \__, | \___| |_.__/ \__, | \__, | \__,_| \__,_| \___/ |_| |_||_||_||_| |_| \___| \___/ \__,_| \__,_| \__, | \___| |_.__/ \__, | \__, | \__,_| \__,_|
|___/ |___/ |_| |___/ |___/ |_|
https://github.com/QingdaoU/OnlineJudge https://github.com/QingdaoU/OnlineJudge
""" """
from __future__ import absolute_import
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app

17
oj/celery.py Normal file
View File

@ -0,0 +1,17 @@
from __future__ import absolute_import
import os
from celery import Celery
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'oj.settings')
from django.conf import settings
app = Celery('oj')
# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

View File

@ -22,6 +22,11 @@ REDIS_CACHE = {
"db": 1 "db": 1
} }
# for celery
REDIS_HOST = "localhost"
REDIS_PORT = 6379
REDIS_DB = 0
DEBUG = True DEBUG = True
ALLOWED_HOSTS = [] ALLOWED_HOSTS = []

View File

@ -31,6 +31,11 @@ REDIS_CACHE = {
"db": 1 "db": 1
} }
# for celery
REDIS_HOST = os.environ.get("REDIS_PORT_6379_TCP_ADDR", "127.0.0.1")
REDIS_PORT = 6379
REDIS_DB = 0
DEBUG = False DEBUG = False
ALLOWED_HOSTS = ['*'] ALLOWED_HOSTS = ['*']

View File

@ -22,6 +22,15 @@ if ENV == "local":
elif ENV == "server": elif ENV == "server":
from .server_settings import * from .server_settings import *
import djcelery
djcelery.setup_loader()
BROKER_BACKEND = "redis"
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@ -51,9 +60,12 @@ INSTALLED_APPS = (
'mq', 'mq',
'contest', 'contest',
'mail', 'mail',
'judge',
'judge_dispatcher',
'django_extensions', 'django_extensions',
'rest_framework', 'rest_framework',
'djcelery',
) )
if DEBUG: if DEBUG:

View File

@ -1,7 +1,7 @@
# coding=utf-8 # coding=utf-8
from django.db import models from django.db import models
from utils.shortcuts import rand_str from utils.shortcuts import rand_str
from judge.judger.result import result from judge.result import result
class Submission(models.Model): class Submission(models.Model):

View File

@ -7,7 +7,7 @@ from django.shortcuts import render
from django.core.paginator import Paginator from django.core.paginator import Paginator
from rest_framework.views import APIView from rest_framework.views import APIView
from judge.judger_controller.tasks import judge from judge_dispatcher.tasks import create_judge_task
from account.decorators import login_required, super_admin_required from account.decorators import login_required, super_admin_required
from account.models import SUPER_ADMIN, User from account.models import SUPER_ADMIN, User
from problem.models import Problem from problem.models import Problem
@ -23,8 +23,8 @@ from .serializers import (CreateSubmissionSerializer, SubmissionSerializer,
logger = logging.getLogger("app_info") logger = logging.getLogger("app_info")
def _judge(submission_id, time_limit, memory_limit, test_case_id): def _judge(submission_id, code, language_code, time_limit, memory_limit, test_case_id):
judge.delay(submission_id, time_limit, memory_limit, test_case_id) create_judge_task.delay(submission_id, code, language_code, time_limit, memory_limit, test_case_id)
get_cache_redis().incr("judge_queue_length") get_cache_redis().incr("judge_queue_length")
@ -49,7 +49,7 @@ class SubmissionAPIView(APIView):
problem_id=problem.id) problem_id=problem.id)
try: try:
_judge(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id) _judge(submission.id, submission.code, submission.language, problem.time_limit, problem.memory_limit, problem.test_case_id)
except Exception as e: except Exception as e:
logger.error(e) logger.error(e)
return error_response(u"提交判题任务失败") return error_response(u"提交判题任务失败")
@ -94,7 +94,7 @@ class ContestSubmissionAPIView(APIView):
code=data["code"], code=data["code"],
problem_id=problem.id) problem_id=problem.id)
try: try:
_judge(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id) _judge(submission.id, submission.code, submission.language, problem.time_limit, problem.memory_limit, problem.test_case_id)
except Exception as e: except Exception as e:
logger.error(e) logger.error(e)
return error_response(u"提交判题任务失败") return error_response(u"提交判题任务失败")
@ -279,7 +279,7 @@ class SubmissionRejudgeAdminAPIView(APIView):
except Problem.DoesNotExist: except Problem.DoesNotExist:
return error_response(u"题目不存在") return error_response(u"题目不存在")
try: try:
_judge(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id) _judge(submission.id, submission.code, submission.language, problem.time_limit, problem.memory_limit, problem.test_case_id)
except Exception as e: except Exception as e:
logger.error(e) logger.error(e)
return error_response(u"提交判题任务失败") return error_response(u"提交判题任务失败")