summaryrefslogtreecommitdiff
path: root/docs/tutorials/zeo/index.rst
blob: 229ec2ffc816230a3e8f1345062c96aff02c27e9 (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
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
.. _zodb_with_zeo:

Using ZODB with ZEO
===================

:term:`ZODB` is a Python object persistence mechanism.  :term:`ZODB`
works well as a storage mechanism for :app:`Pyramid` applications,
especially in applications that use :term:`traversal`.

:term:`ZEO` is an extension to ZODB which allows more than one process
to simultaneously communicate with a ZODB storage.  Making a ZODB
database accessible to more than one process means that you can debug
your application objects at the same time that a :app:`Pyramid`
server that accesses the database is running, and will also allow your
application to run under multiprocess configurations, such as those
exposed by :term:`mod_wsgi`.

The easiest way to get started with ZODB in a :app:`Pyramid` application is
to use the ZODB ``pyramid_zodb`` paster template.  See
:ref:`additional_paster_templates` for more information about using this
template.  However, the Paster template does not set up a ZEO-capable
application.  This chapter shows you how to do that "from scratch".

Installing Dependencies
-----------------------

#. Edit your :app:`Pyramid` application's ``setup.py`` file, adding
   the following packages to the ``install_requires`` of the
   application:

   - ``repoze.folder``

   - ``repoze.retry``

   - ``repoze.tm2``

   - ``repoze.zodbconn``

   For example, the relevant portion of your application's
   ``setup.py`` file might look like so when you're finished adding
   the dependencies.

   .. code-block:: python
      :linenos:

      setup(
          # ... other elements left out for brevity
          install_requires=[
                'pyramid',
                'repoze.folder',
                'repoze.retry',
                'repoze.tm2',
                'repoze.zodbconn',
                ],
          # ... other elements left out for brevity
           )

#. Rerun your application's ``setup.py`` file (e.g. using ``python
   setup.py develop``) to get these packages installed.  A number of
   packages will be installed, including ``ZODB``.  For the purposes
   of this tutorial, we'll assume that your "application" is actually
   just the result of the ``pyramid_starter`` Paster template.

Configuration
-------------

#. Edit your application's Paste ``development.ini`` file.

   If you already have an ``app`` section in the ``.ini`` file named
   ``main``, rename this section to ``myapp`` (e.g. ``app:main`` ->
   ``app:myapp``).  Add a key to it named ``zodb_uri``, e.g.

   .. code-block:: ini

      [app:myapp]
      use = egg:myapp#app
      zodb_uri = zeo://%(here)s/zeo.sock
      reload_templates = true
      debug_authorization = false
      debug_notfound = false

   If a ``pipeline`` named ``main`` does not already exist in the
   paste ``.ini`` file , add a ``pipeline`` section named ``main``.
   Put the names ``connector``, ``egg:repoze.retry#retry``, and
   ``egg:repoze.tm2#tm`` to the top of the pipeline.

   .. code-block:: ini

      [pipeline:main]
      pipeline = 
             egg:repoze.retry#retry
             egg:repoze.tm2#tm
             myapp

   When you're finished, your ``.ini`` file might look like so:

   .. code-block:: ini

      [DEFAULT]
      debug = true

      [app:myapp]
      use = egg:myapp#app
      zodb_uri = zeo://%(here)s/zeo.sock
      reload_templates = true
      debug_authorization = false
      debug_notfound = false

      [pipeline:main]
      pipeline = 
             egg:repoze.retry#retry
             egg:repoze.tm2#tm
             myapp

      [server:main]
      use = egg:Paste#http
      host = 0.0.0.0
      port = 6543

   See :ref:`MyProject_ini` for more information about project Paste
   ``.ini`` files.

#. Add a ``zeo.conf`` file to your package with the following
   contents:

   .. code-block:: text

      %define INSTANCE .

      <zeo>
        address $INSTANCE/zeo.sock
        read-only false
        invalidation-queue-size 100
        pid-filename $INSTANCE/zeo.pid
      </zeo>

      <blobstorage 1>
        <filestorage>
          path $INSTANCE/myapp.db
        </filestorage>
        blob-dir $INSTANCE/blobs
      </blobstorage>

#.  For the purposes of this tutorial we'll assume that you want your
    :app:`Pyramid` application's :term:`root` object to be a
    "folderish" object.  To achieve this, change your application's
    ``models.py`` file to look like the below:

    .. code-block:: python

       from repoze.folder import Folder

       class MyModel(Folder):
           pass

       def appmaker(root):
           if not 'myapp' in root:
               root['myapp'] = MyModel()
               transaction.commit()
           return root['myapp']

#.  Change your application's ``__init__.py`` to look something like the
    below:

    .. code-block:: python

       from pyramid.configuration import Configurator
       from repoze.zodbconn.finder import PersistentApplicationFinder
       from myapp.models import appmaker
       import transaction

       def app(global_config, **settings):
           """ This function returns a ``pyramid`` WSGI 
           application.

           It is usually called by the PasteDeploy framework during
           ``paster serve``"""
           # paster app config callback
           zodb_uri = settings['zodb_uri']
           finder = PersistentApplicationFinder(zodb_uri, appmaker)
           def get_root(request):
               return finder(request.environ)
           config = Configurator(root_factory=get_root, settings=settings)
           # .. other configuration statements ..
           return config.make_wsgi_app()

Running
-------
    
#.  Start the ZEO server in a terminal with the current directory set
    to the package directory:

    .. code-block:: text

       ../bin/runzeo -C zeo.conf

    You should see something like this, as a result:

    .. code-block:: text
       :linenos:

       [chrism@snowpro myapp]$ ../bin/runzeo -C zeo.conf 
       ------
       2009-09-19T13:48:41 INFO ZEO.runzeo (9910) created PID file './zeo.pid'
       # ... more output ...
       2009-09-19T13:48:41 INFO ZEO.zrpc (9910) listening on ./zeo.sock

#.  While the ZEO server is running, start the application server:

    .. code-block:: text
       :linenos:

       [chrism@snowpro myapp]$ ../bin/paster serve myapp.ini 
       Starting server in PID 10177.
       serving on 0.0.0.0:6543 view at http://127.0.0.1:6543

#.  The root object is now a "folderish" ZODB object.  Nothing else
    about the application has changed.  

#.  You can manipulate the database directly (even when the
    application's HTTP server is running) by using the ``pshell``
    command in a third terminal window:

    .. code-block:: text
       :linenos:

       [chrism@snowpro sess]$ ../bin/paster --plugin=pyramid pshell \
              myapp.ini myapp
       Python 2.5.4 (r254:67916, Sep  4 2009, 02:12:16) 
       [GCC 4.2.1 (Apple Inc. build 5646)] on darwin
       Type "help" for more information. "root" is the Pyramid app root object.
       >>> root
       <sess.models.MyModel object None at 0x16438f0>
       >>> root.foo = 'bar'
       >>> import transaction
       >>> transaction.commit()