Oslo.service migration examples¶
This example shows the same application with oslo.service and cotyledon. It uses a wide range of API of oslo.service, but most applications don’t really uses all of this. In most case cotyledon.ServiceManager don’t need to inherited.
It doesn’t show how to replace the periodic task API, if you use it you should take a look to futurist documentation
oslo.service typical application:
import multiprocessing
from oslo.service import service
from oslo.config import cfg
class MyService(service.Service):
def __init__(self, conf):
# called before os.fork()
self.conf = conf
self.master_pid = os.getpid()
self.queue = multiprocessing.Queue()
def start(self):
# called when application start (parent process start)
# and
# called just after os.fork()
if self.master_pid == os.getpid():
do_master_process_start()
else:
task = self.queue.get()
do_child_process_start(task)
def stop(self):
# called when children process stop
# and
# called when application stop (parent process stop)
if self.master_pid == os.getpid():
do_master_process_stop()
else:
do_child_process_stop()
def restart(self):
# called on SIGHUP
if self.master_pid == os.getpid():
do_master_process_reload()
else:
# Can't be reach oslo.service currently prefers to
# kill the child process for safety purpose
do_child_process_reload()
class MyOtherService(service.Service):
pass
class MyThirdService(service.Service):
pass
def main():
conf = cfg.ConfigOpts()
service = MyService(conf)
launcher = service.launch(conf, service, workers=2, restart_method='reload')
launcher.launch_service(MyOtherService(), worker=conf.other_workers)
# Obviously not recommanded, because two objects will handle the
# lifetime of the masterp process but some application does this, so...
launcher2 = service.launch(conf, MyThirdService(), workers=2, restart_method='restart')
launcher.wait()
launcher2.wait()
# Here, we have no way to change the number of worker dynamically.
Cotyledon version of the typical application:
import cotyledon
from cotyledon import oslo_config_glue
class MyService(cotyledon.Service):
name = "MyService fancy name that will showup in 'ps xaf'"
# Everything in this object will be called after os.fork()
def __init__(self, worker_id, conf, queue):
self.conf = conf
self.queue = queue
def run(self):
# Optional method to run the child mainloop or whatever
task = self.queue.get()
do_child_process_start(task)
def terminate(self):
do_child_process_stop()
def reload(self):
# Done on SIGHUP after the configuration file reloading
do_child_reload()
class MyOtherService(cotyledon.Service):
name = "Second Service"
class MyThirdService(cotyledon.Service):
pass
class MyServiceManager(cotyledon.ServiceManager):
def __init__(self, conf)
super(MetricdServiceManager, self).__init__()
self.conf = conf
oslo_config_glue.setup(self, self.conf, restart_method='reload')
self.queue = multiprocessing.Queue()
# the queue is explicitly passed to this child (it will live
# on all of them due to the usage of os.fork() to create children)
sm.add(MyService, workers=2, args=(self.conf, queue))
self.other_id = sm.add(MyOtherService, workers=conf.other_workers)
sm.add(MyThirdService, workers=2)
def run(self):
do_master_process_start()
super(MyServiceManager, self).run()
do_master_process_stop()
def reload(self):
# The cotyledon ServiceManager have already reloaded the oslo.config files
do_master_process_reload()
# Allow to change the number of worker for MyOtherService
self.reconfigure(self.other_id, workers=self.conf.other_workers)
def main():
conf = cfg.ConfigOpts()
MyServiceManager(conf).run()
Other examples can be found here: