1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
|
#!/usr/bin/env python
from tornado.options import options, define, parse_command_line
import django.core.handlers.wsgi
import tornado.httpserver
import tornado.ioloop
import tornado.web
import tornado.wsgi
import os, sys
import django
import time
import signal
import logging
from functools import partial
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options
MAX_WAIT_SECONDS_BEFORE_SHUTDOWN = 3
#pid = str(os.getpid())
#f = open(os.environ['SOC_PID'], 'w')
#f.write(pid)
#f.close()
django.setup()
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "R_on_Cloud.settings")
from concurrent.futures import ThreadPoolExecutor
from tornado import gen
from instances import execute_code
import threading
import pwd
from R_on_Cloud.config import TORNADO_IP, TORNADO_PORT
define('port', type=int, default=TORNADO_PORT)
define("ip", default=TORNADO_IP, help="Run on any given IP", type=str)
# Custom settings
from R_on_Cloud.settings import PROJECT_DIR
from django.core.wsgi import get_wsgi_application
#Gist
def sig_handler(server, sig, frame):
io_loop = tornado.ioloop.IOLoop.instance()
def stop_loop(deadline):
now = time.time()
#if now < deadline:
if now < deadline and (io_loop._callbacks or io_loop._timeouts):
logging.info('Waiting for next tick')
io_loop.add_timeout(now + 1, stop_loop, deadline)
else:
io_loop.stop()
logging.info('Shutdown finally')
def shutdown():
logging.info('Stopping Django DB connections...')
from django.db import connections
for conn in connections.all():
conn.close()
logging.info('Stopping http server')
server.stop()
logging.info('Will shutdown in %s seconds ...',
MAX_WAIT_SECONDS_BEFORE_SHUTDOWN)
stop_loop(time.time() + MAX_WAIT_SECONDS_BEFORE_SHUTDOWN)
logging.warning('Caught signal: %s', sig)
io_loop.add_callback_from_signal(shutdown)
#End Gist
def run_as_nobody():
"""Runs the current process as nobody."""
# Set the effective uid and to that of nobody.
nobody = pwd.getpwnam('nobody')
os.setegid(nobody.pw_gid)
os.seteuid(nobody.pw_uid)
# request_count keeps track of the number of requests at hand, it is incremented
# when post method is invoked and decremented before exiting post method in
# class ExecutionHandler.
DEFAULT_WORKERS = 5
request_count = 0
# ThreadPoolExecutor is an Executor subclass that uses a pool of threads to
# execute
# function calls asynchronously.
# It runs numbers of threads equal to DEFAULT_WORKERS in the background.
executor = ThreadPoolExecutor(max_workers=DEFAULT_WORKERS)
# instance_manager function is run at a fixed interval to kill the
# Scilab instances not in use. If the number of user requests is more than the
# count of active Scilab instances, maximum instances defined will be in
# process. Instances will be killed only when their number is more than the user
# requests.
# Whenever django server sends an ajax request,
# the request is handled by the ExecutionHandler
# post method passes all the parameters received from the ajax call and
# passes it to the submit method of ThreadPoolExecutor class through its object.
# yield is used to gather the output asynchronously in the variable data
class ExecutionHandler(tornado.web.RequestHandler):
@gen.coroutine
def post(self):
global request_count
request_count += 1
user_id = self.request.arguments['user_id'][0]
R_file_id = str(time.time())
code = self.request.arguments['code'][0]
data = yield executor.submit(execute_code, code.decode("utf-8"), user_id, R_file_id)
self.write(data)
request_count -= 1
def main():
parse_command_line()
wsgi_app = tornado.wsgi.WSGIContainer(
get_wsgi_application())
tornado_app = tornado.web.Application(
[
('/execute-code', ExecutionHandler),
('/static/(.*)', tornado.web.StaticFileHandler,
{'path': PROJECT_DIR + '/static/'}),
('.*', tornado.web.FallbackHandler, dict(fallback=wsgi_app)),
], debug=False)
server = tornado.httpserver.HTTPServer(tornado_app)
server.listen(options.port, options.ip)
try:
#server.start(0)
tornado.ioloop.IOLoop.instance().start()
# signal : CTRL + BREAK on windows or CTRL + C on linux
except KeyboardInterrupt:
signal.signal(signal.SIGTERM, partial(sig_handler, server))
signal.signal(signal.SIGQUIT, partial(sig_handler, server))
sys.exit(0)
#Gist
logging.info("Exit...")
#End Gist
if __name__ == '__main__':
main()
|