|  | @@ -1,9 +1,8 @@
 | 
	
		
			
			| 1 | 1 |  import threading
 | 
	
		
			
			|  | 2 | +import collections
 | 
	
		
			
			| 2 | 3 |  from configparser import DuplicateSectionError
 | 
	
		
			
			| 3 |  | -from wsgiref.simple_server import make_server
 | 
	
		
			
			| 4 |  | -import signal
 | 
	
		
			
			| 5 | 4 |  
 | 
	
		
			
			| 6 |  | -import collections
 | 
	
		
			
			|  | 5 | +from wsgiref.simple_server import make_server
 | 
	
		
			
			| 7 | 6 |  
 | 
	
		
			
			| 8 | 7 |  from radicale import Application as RadicaleApplication
 | 
	
		
			
			| 9 | 8 |  from radicale import HTTPServer as BaseRadicaleHTTPServer
 | 
	
	
		
			
			|  | @@ -13,16 +12,18 @@ from radicale import config as radicale_config
 | 
	
		
			
			| 13 | 12 |  from rq import Connection as RQConnection
 | 
	
		
			
			| 14 | 13 |  from rq import Worker as BaseRQWorker
 | 
	
		
			
			| 15 | 14 |  from redis import Redis
 | 
	
		
			
			|  | 15 | +from rq.dummy import do_nothing
 | 
	
		
			
			|  | 16 | +from rq.worker import StopRequested
 | 
	
		
			
			| 16 | 17 |  
 | 
	
		
			
			| 17 | 18 |  from tracim.lib.base import logger
 | 
	
		
			
			| 18 | 19 |  from tracim.lib.exceptions import AlreadyRunningDaemon
 | 
	
		
			
			| 19 |  | -from tracim.lib.utils import add_signal_handler
 | 
	
		
			
			|  | 20 | +
 | 
	
		
			
			|  | 21 | +from tracim.lib.utils import get_rq_queue
 | 
	
		
			
			| 20 | 22 |  
 | 
	
		
			
			| 21 | 23 |  
 | 
	
		
			
			| 22 | 24 |  class DaemonsManager(object):
 | 
	
		
			
			| 23 | 25 |      def __init__(self):
 | 
	
		
			
			| 24 | 26 |          self._running_daemons = {}
 | 
	
		
			
			| 25 |  | -        add_signal_handler(signal.SIGTERM, self.stop_all)
 | 
	
		
			
			| 26 | 27 |  
 | 
	
		
			
			| 27 | 28 |      def run(self, name: str, daemon_class: object, **kwargs) -> None:
 | 
	
		
			
			| 28 | 29 |          """
 | 
	
	
		
			
			|  | @@ -61,7 +62,7 @@ class DaemonsManager(object):
 | 
	
		
			
			| 61 | 62 |              logger.info(self, 'Stopping daemon with name "{0}": OK'
 | 
	
		
			
			| 62 | 63 |                                .format(name))
 | 
	
		
			
			| 63 | 64 |  
 | 
	
		
			
			| 64 |  | -    def stop_all(self, *args, **kwargs) -> None:
 | 
	
		
			
			|  | 65 | +    def stop_all(self) -> None:
 | 
	
		
			
			| 65 | 66 |          """
 | 
	
		
			
			| 66 | 67 |          Stop all started daemons and wait for them.
 | 
	
		
			
			| 67 | 68 |          """
 | 
	
	
		
			
			|  | @@ -71,6 +72,10 @@ class DaemonsManager(object):
 | 
	
		
			
			| 71 | 72 |              daemon.stop()
 | 
	
		
			
			| 72 | 73 |  
 | 
	
		
			
			| 73 | 74 |          for name, daemon in self._running_daemons.items():
 | 
	
		
			
			|  | 75 | +            logger.info(
 | 
	
		
			
			|  | 76 | +                self,
 | 
	
		
			
			|  | 77 | +                'Stopping daemon "{0}" waiting confirmation'.format(name),
 | 
	
		
			
			|  | 78 | +            )
 | 
	
		
			
			| 74 | 79 |              daemon.join()
 | 
	
		
			
			| 75 | 80 |              logger.info(self, 'Stopping daemon "{0}" OK'.format(name))
 | 
	
		
			
			| 76 | 81 |  
 | 
	
	
		
			
			|  | @@ -158,7 +163,12 @@ class MailSenderDaemon(Daemon):
 | 
	
		
			
			| 158 | 163 |          pass
 | 
	
		
			
			| 159 | 164 |  
 | 
	
		
			
			| 160 | 165 |      def stop(self) -> None:
 | 
	
		
			
			| 161 |  | -        self.worker.request_stop('TRACIM STOP', None)
 | 
	
		
			
			|  | 166 | +        # When _stop_requested at False, tracim.lib.daemons.RQWorker
 | 
	
		
			
			|  | 167 | +        # will raise StopRequested exception in worker thread after receive a
 | 
	
		
			
			|  | 168 | +        # job.
 | 
	
		
			
			|  | 169 | +        self.worker._stop_requested = True
 | 
	
		
			
			|  | 170 | +        queue = get_rq_queue('mail_sender')
 | 
	
		
			
			|  | 171 | +        queue.enqueue(do_nothing)
 | 
	
		
			
			| 162 | 172 |  
 | 
	
		
			
			| 163 | 173 |      def run(self) -> None:
 | 
	
		
			
			| 164 | 174 |          from tracim.config.app_cfg import CFG
 | 
	
	
		
			
			|  | @@ -175,13 +185,19 @@ class MailSenderDaemon(Daemon):
 | 
	
		
			
			| 175 | 185 |  
 | 
	
		
			
			| 176 | 186 |  class RQWorker(BaseRQWorker):
 | 
	
		
			
			| 177 | 187 |      def _install_signal_handlers(self):
 | 
	
		
			
			| 178 |  | -        # TODO BS 20170126: RQ WWorker is designed to work in main thread
 | 
	
		
			
			|  | 188 | +        # RQ Worker is designed to work in main thread
 | 
	
		
			
			| 179 | 189 |          # So we have to disable these signals (we implement server stop in
 | 
	
		
			
			| 180 |  | -        # MailSenderDaemon.stop method). When bug
 | 
	
		
			
			| 181 |  | -        # https://github.com/tracim/tracim/issues/166 will be fixed, ensure
 | 
	
		
			
			| 182 |  | -        # This worker terminate correctly.
 | 
	
		
			
			|  | 190 | +        # MailSenderDaemon.stop method).
 | 
	
		
			
			| 183 | 191 |          pass
 | 
	
		
			
			| 184 | 192 |  
 | 
	
		
			
			|  | 193 | +    def dequeue_job_and_maintain_ttl(self, timeout):
 | 
	
		
			
			|  | 194 | +        # RQ Worker is designed to work in main thread, so we add behaviour
 | 
	
		
			
			|  | 195 | +        # here: if _stop_requested has been set to True, raise the standard way
 | 
	
		
			
			|  | 196 | +        # StopRequested exception to stop worker.
 | 
	
		
			
			|  | 197 | +        if self._stop_requested:
 | 
	
		
			
			|  | 198 | +            raise StopRequested()
 | 
	
		
			
			|  | 199 | +        return super().dequeue_job_and_maintain_ttl(timeout)
 | 
	
		
			
			|  | 200 | +
 | 
	
		
			
			| 185 | 201 |  
 | 
	
		
			
			| 186 | 202 |  class RadicaleHTTPSServer(TracimSocketServerMixin, BaseRadicaleHTTPSServer):
 | 
	
		
			
			| 187 | 203 |      pass
 |