Skip to content

Commit 2f67d5e

Browse files
Forbes BearForbes Bear
authored andcommitted
add thread pool
1 parent c57c7ef commit 2f67d5e

File tree

3 files changed

+49
-31
lines changed

3 files changed

+49
-31
lines changed

src/ansible_api/config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class Config(object):
2525
sign_key = 'YOUR_SIGNATURE_KEY_HERE'
2626
log_path = '/var/log/ansible-api.log'
2727
allow_ip = []
28-
thread_pool_size = cpu_count() * 2 # adapt the number of thread pool size to the number of cpu cores
28+
thread_pool_size = cpu_count() // 2 # adapt the number of thread pool size to the number of cpu cores
2929

3030
dir_script = ''
3131
dir_playbook = ''

src/ansible_api/controller.py

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@
1717
import ansible_runner
1818

1919
from jinja2 import Environment, meta
20+
2021
from tornado.web import RequestHandler, HTTPError
22+
from tornado.concurrent import run_on_executor
23+
from concurrent.futures import ThreadPoolExecutor
24+
25+
import tornado.gen
2126

2227
from .tool import Tool
2328
from .config import Config
@@ -60,24 +65,31 @@ def get(self):
6065
{'message': "Hello, I am Ansible Api", 'rc': ErrorCode.ERRCODE_NONE}))
6166

6267

63-
class AsyncTest(Controller):
68+
class NonBlockTest(Controller):
69+
executor = ThreadPoolExecutor(4)
6470

71+
@tornado.gen.coroutine
6572
def get(self):
66-
self.finish(Tool.jsonal(
67-
{'message': 'hi test', 'rc': ErrorCode.ERRCODE_NONE}))
73+
start = time.time()
74+
msg = yield self.run_block()
75+
end = time.time() - start
76+
self.write(Tool.jsonal({'message': msg + 'and total cost time: %s' % end, 'rc': ErrorCode.ERRCODE_NONE}))
6877

69-
async def test(self):
78+
@run_on_executor
79+
def run_block(self):
7080
time.sleep(10)
7181
return 'i have slept 10 s'
7282

7383

7484
class Command(Controller):
85+
executor = ThreadPoolExecutor(Config.get('thread_pool_size'))
7586

7687
def get(self):
7788
self.finish(Tool.jsonal(
7889
{'error': "Forbidden in get method", 'rc': ErrorCode.ERRCODE_SYS}))
7990

80-
async def post(self): # Change the async method to python3 async, this performance better than gen.coroutine
91+
@tornado.gen.coroutine
92+
def post(self): # Change the async method to python3 async, this performance better than gen.coroutine
8193
data = Tool.parsejson(self.request.body)
8294
bad_cmd = ['reboot', 'su', 'sudo', 'dd',
8395
'mkfs', 'shutdown', 'half', 'top']
@@ -106,27 +118,33 @@ async def post(self): # Change the async method to python3 async, this performa
106118
cb.status_drawer(dict(status='starting', raw=lambda: dict(
107119
task_name=module, event='playbook_on_play_start', runner_ident=name,
108120
event_data=dict(pattern=target, name=module)),
109-
after=lambda: dict(task_list=[module])))
110-
response = ansible_runner.interface.run(
111-
host_pattern=target, inventory='/etc/ansible/hosts',
112-
envvars=dict(PATH=os.environ.get('PATH')+':'+sys.path[0]),
113-
ident=name, module=module, module_args=arg,
114-
event_handler=cb.event_handler, status_handler=cb.status_handler
115-
)
116-
# pp = pprint.PrettyPrinter(indent=4)
117-
# print('*' * 20)
118-
# pp.pprint(cb.get_summary())
119-
# print('+' * 20)
120-
self.finish(Tool.jsonal(dict(rc=response.rc, detail=cb.get_summary())))
121+
after=lambda: dict(task_list=[module])))
122+
response = yield self.run(target, name, module, arg, cb)
123+
self.write(Tool.jsonal(dict(rc=response.rc, detail=cb.get_summary())))
121124
except Exception as e:
122125
Tool.LOGGER.exception(e)
123-
self.finish(Tool.jsonal(
126+
self.write(Tool.jsonal(
124127
{'error': str(e), 'rc': ErrorCode.ERRCODE_BIZ}))
125128

129+
@run_on_executor
130+
def run(self, target, name, module, arg, cb):
131+
return ansible_runner.interface.run(
132+
host_pattern=target, inventory='/etc/ansible/hosts',
133+
envvars=dict(PATH=os.environ.get('PATH') + ':' + sys.path[0]),
134+
ident=name, module=module, module_args=arg,
135+
event_handler=cb.event_handler, status_handler=cb.status_handler
136+
)
137+
126138

127139
class Playbook(Controller):
140+
executor = ThreadPoolExecutor(Config.get('thread_pool_size'))
128141

129-
async def post(self):
142+
def get(self):
143+
self.finish(Tool.jsonal(
144+
{'error': "Forbidden in get method", 'rc': ErrorCode.ERRCODE_SYS}))
145+
146+
@tornado.gen.coroutine
147+
def post(self):
130148
data = Tool.parsejson(self.request.body)
131149
Tool.LOGGER.debug("MORE DETAIL: data %s" % data)
132150
name = data['n'].encode('utf-8').decode()
@@ -165,16 +183,7 @@ async def post(self):
165183
try:
166184
cb = CallBack()
167185
cb.event_pepper('playbook_on_play_start', dict(task_list=task_list))
168-
response = ansible_runner.interface.run(
169-
host_pattern=hosts, inventory='/etc/ansible/hosts',
170-
envvars=dict(PATH=os.environ.get('PATH')+':'+sys.path[0]),
171-
playbook=yml_file, ident=name, extravars=my_vars,
172-
event_handler=cb.event_handler, status_handler=cb.status_handler
173-
)
174-
# pp = pprint.PrettyPrinter(indent=4)
175-
# print('*' * 20)
176-
# pp.pprint(cb.get_summary())
177-
# print('+' * 20)
186+
response = yield self.run(hosts, name, yml_file, my_vars, cb)
178187
self.finish(Tool.jsonal(dict(rc=response.rc, detail=cb.get_summary())))
179188
except BaseException as e:
180189
Tool.LOGGER.exception(e)
@@ -185,6 +194,15 @@ async def post(self):
185194
self.finish(Tool.jsonal(
186195
{'error': "yml file(" + yml_file + ") is not existed", 'rc': ErrorCode.ERRCODE_SYS}))
187196

197+
@run_on_executor
198+
def run(self, hosts, name, yml_file, my_vars, cb):
199+
return ansible_runner.interface.run(
200+
host_pattern=hosts, inventory='/etc/ansible/hosts',
201+
envvars=dict(PATH=os.environ.get('PATH') + ':' + sys.path[0]),
202+
playbook=yml_file, ident=name, extravars=my_vars,
203+
event_handler=cb.event_handler, status_handler=cb.status_handler
204+
)
205+
188206

189207
class FileList(Controller):
190208

src/ansible_api/webapi.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class WebApi(object):
2727
def __init__(self):
2828
application = web.Application([
2929
(r'/', controller.Main),
30-
(r'/asynctest', controller.AsyncTest),
30+
(r'/test', controller.NonBlockTest),
3131
(r'/command', controller.Command),
3232
(r'/playbook', controller.Playbook),
3333
(r'/parsevars', controller.ParseVarsFromFile),

0 commit comments

Comments
 (0)