11import sys
22import logging
3+ from urllib .parse import quote
34
45from concurrent .futures import ThreadPoolExecutor
56
@@ -37,21 +38,21 @@ class Flower(tornado.web.Application):
3738
3839 def __init__ (self , options = None , capp = None , events = None ,
3940 io_loop = None , ** kwargs ):
41+
4042 handlers = default_handlers
4143 if options is not None and options .url_prefix :
4244 handlers = [rewrite_handler (h , options .url_prefix ) for h in handlers ]
4345 kwargs .update (handlers = handlers )
46+
4447 super ().__init__ (** kwargs )
48+
4549 self .options = options or default_options
4650 self .io_loop = io_loop or ioloop .IOLoop .instance ()
4751 self .ssl_options = kwargs .get ('ssl_options' , None )
4852
4953 self .capp = capp or celery .Celery ()
5054 self .capp .loader .import_default_modules ()
5155
52- self .executor = self .pool_executor_cls (max_workers = self .max_workers )
53- self .io_loop .set_default_executor (self .executor )
54-
5556 self .inspector = Inspector (self .io_loop , self .capp , self .options .inspect_timeout / 1000.0 )
5657
5758 self .events = events or Events (
@@ -63,33 +64,85 @@ def __init__(self, options=None, capp=None, events=None,
6364 io_loop = self .io_loop ,
6465 max_workers_in_memory = self .options .max_workers ,
6566 max_tasks_in_memory = self .options .max_tasks )
66- self .started = False
6767
68- def start (self ):
68+ self ._http_server = None
69+ self ._executor = None
70+
71+ def _start_executor (self ):
72+ if self ._executor is None :
73+ logging .debug ("Starting executor..." )
74+ ctx = self .pool_executor_cls (max_workers = self .max_workers )
75+ self ._executor = ctx .__enter__ ()
76+ self .io_loop .set_default_executor (self ._executor )
77+
78+ def _stop_executor (self ):
79+ if self ._executor is not None :
80+ logging .debug ("Stop executor..." )
81+ self ._executor .__exit__ (None , None , None )
82+ self ._executor = None
83+
84+ def _start_events (self ):
85+ logging .debug ("Starting event..." )
6986 self .events .start ()
7087
88+ def _stop_events (self ):
89+ logging .debug ("Stopping event..." )
90+ self .events .stop ()
91+
92+ def _start_http_server (self ):
93+ logging .debug ("Starting HTTP server..." )
7194 if not self .options .unix_socket :
72- self .listen (self .options .port , address = self .options .address ,
73- ssl_options = self .ssl_options ,
74- xheaders = self .options .xheaders )
95+ http_server = self .listen (
96+ self .options .port ,
97+ address = self .options .address ,
98+ ssl_options = self .ssl_options ,
99+ xheaders = self .options .xheaders
100+ )
75101 else :
76102 from tornado .netutil import bind_unix_socket
77- server = HTTPServer (self )
78- socket = bind_unix_socket (self .options .unix_socket , mode = 0o777 )
79- server .add_socket (socket )
80103
81- self .started = True
82- self .update_workers ()
104+ http_server = HTTPServer (self )
105+ socket = bind_unix_socket (self .options .unix_socket , mode = 0o777 )
106+ http_server .add_socket (socket )
107+ self ._http_server = http_server
108+
109+ def _stop_http_server (self ):
110+ logging .debug ("Stopping HTTP server..." )
111+ self .io_loop .run_sync (
112+ self ._http_server .close_all_connections , timeout = 5
113+ )
114+ self ._http_server .stop ()
115+ self ._http_server = None
116+
117+ def start_server (self ):
118+ if self ._http_server is not None :
119+ logging .debug ("Flower server already started." )
120+ return
121+ self ._start_executor ()
122+ self ._start_events ()
123+ self ._start_http_server ()
124+ logging .debug ("Flower server started." )
125+
126+ def stop_server (self ):
127+ if self ._http_server is None :
128+ logging .debug ("Flower server already stopped." )
129+ return
130+ self ._stop_events ()
131+ self ._stop_http_server ()
132+ self ._stop_executor ()
133+ logging .debug ("Flower server stopped." )
134+
135+ def serve_forever (self ):
136+ if not self ._http_server :
137+ raise RuntimeError ("The server is not running" )
138+ logging .debug ("Starting event loop..." )
83139 self .io_loop .start ()
84140
85- def stop (self ):
86- if self .started :
87- self .events .stop ()
88- logging .debug ("Stopping executors..." )
89- self .executor .shutdown (wait = False )
90- logging .debug ("Stopping event loop..." )
91- self .io_loop .stop ()
92- self .started = False
141+ def shutdown (self ):
142+ if self ._http_server :
143+ raise RuntimeError ("The server is still running" )
144+ logging .debug ("Stopping event loop..." )
145+ self .io_loop .stop ()
93146
94147 @property
95148 def transport (self ):
@@ -101,3 +154,74 @@ def workers(self):
101154
102155 def update_workers (self , workername = None ):
103156 return self .inspector .inspect (workername )
157+
158+ def _get_scheme (self ):
159+ if self .options .unix_socket :
160+ return "http+unix"
161+ elif self .ssl_options :
162+ return "https"
163+ else :
164+ return "http"
165+
166+ def _get_domain (self ):
167+ if self .options .unix_socket :
168+ raise RuntimeError ("UNIX socket" )
169+
170+ if hasattr (self ._http_server , "_sockets" ) and self ._http_server ._sockets :
171+ sock = list (self ._http_server ._sockets .values ())[0 ]
172+ return sock .getsockname ()[0 ]
173+ else :
174+ return self .options .address or "0.0.0.0"
175+
176+ def _get_port (self ):
177+ if self .options .unix_socket :
178+ raise RuntimeError ("UNIX socket" )
179+
180+ if hasattr (self ._http_server , "_sockets" ) and self ._http_server ._sockets :
181+ sock = list (self ._http_server ._sockets .values ())[0 ]
182+ return sock .getsockname ()[1 ]
183+ else :
184+ return self .options .port
185+
186+ def _get_authority (self ):
187+ if self .options .unix_socket :
188+ return quote (self .options .unix_socket )
189+ return f"{ self ._get_domain ()} :{ self ._get_port ()} "
190+
191+ def _get_url_path (self , path = None , include_prefix = True ):
192+ if not include_prefix or not self .options .url_prefix :
193+ return path or ""
194+ prefix = self .options .url_prefix .strip ("/" )
195+ return f"/{ prefix } { path or '' } "
196+
197+ def get_url (self , path = None , include_prefix = True ):
198+ path = self ._get_url_path (path , include_prefix = include_prefix )
199+ return f"{ self ._get_scheme ()} ://{ self ._get_authority ()} { path } "
200+
201+ #
202+ # For backward compatibility
203+ #
204+
205+ def start (self ):
206+ self .start_server ()
207+ self .update_workers ()
208+ self .serve_forever ()
209+
210+ def stop (self ):
211+ self .stop_server ()
212+ self .shutdown ()
213+
214+ @property
215+ def started (self ):
216+ return self ._http_server is not None
217+
218+ @started .setter
219+ def started (self , value ):
220+ if value :
221+ self .start_server ()
222+ else :
223+ self .stop_server ()
224+
225+ @property
226+ def executor (self ):
227+ return self ._executor
0 commit comments