File: oslo-service-migration.rst

package info (click to toggle)
python-cotyledon 1.7.3-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 252 kB
  • sloc: python: 1,067; sh: 34; makefile: 23
file content (157 lines) | stat: -rw-r--r-- 4,972 bytes parent folder | download | duplicates (3)
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
157
===============================
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:

.. code-block:: python

    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:

.. code-block:: python

    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:

* :doc:`examples`
* https://github.com/openstack/gnocchi/blob/master/gnocchi/cli.py#L287
* https://github.com/openstack/ceilometer/blob/master/ceilometer/cmd/collector.py

.. _futurist documentation: <http://docs.openstack.org/developer/futurist/api.html#periodics>`