summaryrefslogtreecommitdiff
path: root/vendor/CherryPy-3.2.0/sphinx/source/progguide/extending/customplugins.rst
blob: 609f5c59bbb7adbfae7754ca75111c2b7e61c465 (plain)
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
**************
Custom Plugins
**************

CherryPy allows you to extend startup, shutdown, and other behavior outside the
request process via *Listeners* and *Plugins*. The
:class:`cherrypy.engine<cherrypy.process.wspbus.Bus>` object controls
these behaviors; to extend them, you subscribe listeners to the engine.
These allow you to run functions at a particular point in the
*site* process; for the *request* process, see :doc:`customtools` instead.

Listeners
=========

The engine is a publish-subscribe service; event handlers publish to various
*channels*, like "start", "stop", "exit", "graceful", or "log", and both
CherryPy and you can subscribe *listeners* for those messages::

    engine.subscribe(channel, callback[, priority])

channel
-------

The channel is an event name:

 * start: the Engine is starting for the first time, or has been stopped and is
   now restarting; listeners here should start up sockets, files, or other
   services and not return until they are ready to be used by clients or
   other parts of the site.
 * stop: the Engine is stopping; plugins should cleanly stop what they are
   doing and not return until they have finished cleaning up. This is called
   by :func:`cherrypy.engine.stop<cherrypy.process.wspbus.Bus.stop>`, and
   plugins should make every effort to stop and clean up in a fashion that
   permits them to be restarted via a "start" listener.
 * graceful: advises all listeners to reload, e.g. by closing any open files
   and reopening them.
 * exit: this is called by
   :func:`cherrypy.engine.exit<cherrypy.process.wspbus.Bus.exit>`,
   and advises plugins to prepare for process termination. Note that
   :func:`cherrypy.engine.exit<cherrypy.process.wspbus.Bus.exit>` first calls
   :func:`cherrypy.engine.stop<cherrypy.process.wspbus.Bus.stop>`, so Plugins
   may expect to stop first, then exit in a separate step.
 * log(msg, level): in general, :class:`cherrypy.log<cherrypy._cplogging.LogManager>`
   listens on this channel. Plugins, however, should make every effort to
   publish to this channel verbosely to aid process event debugging. See the
   builtin Plugins for good examples.
 * main: New in 3.2. All Engine tasks run in threads other than the main thread;
   the main thread usually calls
   :func:`cherrypy.engine.block<cherrypy.process.wspbus.Bus.block>` to wait
   for KeyboardInterrupt and other signals. While blocked, it loops
   (every 1/10th of a second, by default), and publishes a message on the
   "main" channel each time. Listeners subscribed to this channel, therefore,
   are called at every interval.

callback
--------

The functionality you wish to run; this can be any function, class, or other
callable. Each channel defines the arguments; currently, however, only the "log"
channel defines any ('msg', the string message to log, and 'level', an int
following the levels defined in the stdlib's :mod:`logging <logging>` module).

priority
--------

The optional priority (0 - 100) allows multiple listeners to run in the correct
order. Lower numbers run first. The default is 50.

If you omit the priority argument to engine.subscribe (or pass ``None``),
you can instead set it as an attribute on the callback function::

    def setup_db():
        ....
    setup_db.priority = 90
    engine.subscribe('start', setup_db)


Plugins
=======

You can manually subscribe bus listeners, but you probably shouldn't.
*Plugins* allow your function to be subscribed and configured both
via the CherryPy config system and via the Plugin itself. Plugins also allow
you to write a single class that listens on multiple channels.

Most of the built-in plugins have their own ``subscribe`` method,
so that instead of writing ``engine.subscribe``, you write:
``p = Plugin(engine).subscribe()``. If you want to turn off a plugin,
call ``p.unsubscribe()``. The plugin already knows the correct channel,
callback, and priority.

You can run arbitrary code at any of the events by creating a
SimplePlugin object, with one method for each *channel* you wish to handle::

    class ScratchDB(plugins.SimplePlugin):
        
        def start(self):
            self.fname = 'myapp_%d.db' % os.getpid()
            self.db = sqlite.connect(database=self.fname)
        start.priority = 80
        
        def stop(self):
            self.db.close()
            os.remove(self.fname)
    cherrypy.engine.scratchdb = ScratchDB(cherrypy.engine)

...then, once you've authored your Plugin, turn it on by calling its
``subscribe`` method::

    cherrypy.engine.scratchdb.subscribe()

...or, in CherryPy 3.2 and above, in site config::

    [global]
    engine.scratchdb.on = True


Priorities of the built-in "start" listeners:

======================================================================  ================
 Listener                                                               Priority        
======================================================================  ================
 default                                                                50              
 :doc:`Daemonizer </refman/process/plugins/daemonizer>`                 65              
 :doc:`Timeout Monitor </progguide/responsetimeouts>`                   70              
 :class:`Autoreloader <cherrypy.process.plugins.Autoreloader>`          70              
 :doc:`PID File </refman/process/plugins/pidfile>`                      70              
 :doc:`HTTP Servers </refman/process/servers>`                          75              
 :doc:`Drop Privileges </refman/process/plugins/dropprivileges>`        77              
======================================================================  ================