Re: [Zope] Zope and Threads
Dieter Maurer wrote:
alan runyan wrote at 2003-7-9 13:06 -0500:
Just wanted to post this for whoever searches for Zope, Threads and ZSQLMethods or relational databases in the future. It seems that very simplistic things will work if you spawn a thread inside of Zope. But in the thread if you start doing anything really related to ZODB you could have all sorts of issues.
The mailing list archives have some threads about this...
Just checking that I understand the whole thing correctly?
There are a few issues you must observe:
In general you must not share a ZODB connection between threads. This means, you must not pass persistent objects between threads (as they contain a hidden reference to a ZODB connection (_p_jar) and may use it non-deterministically).
Open a new ZODB connection in the new thread. Its "root()" method returns the ZODB root object.
I guess it would look something like this? import Globals db=Globals.DB connection=db.open() root = connection.root()
Pass an object's path between threads rather than the object itself. Use "[un]restrictedTraverse" to locate the object from the root given the path.
Do not forget to commit/abort the (implicitly) started transaction.
Using get_transaction().commit() and get_transaction().abort() as usual I guess?
Do not forget to close the opened ZODB connection
With: connection.close() What about connection.sync(), I would think it syncs commited data fin other threads back to this connection? In other words I need to use this in my thread to get an updated view of the database. Is this correct? Johan -- Johan Carlsson Tel: + 46 8 31 24 94 Colliberty Mob: + 46 70 558 25 24 Torsgatan 72 Email: johanc@easypublisher.com SE-113 37 STOCKHOLM
--On Freitag, 11. Juli 2003 13:01 +0200 Johan Carlsson <johanc@easypublisher.com> wrote:
I guess it would look something like this?
import Globals db=Globals.DB connection=db.open() root = connection.root()
Note here that the ZODB root is *not* the Zope application object! If you want the Zope root folder do this: import Zope app = Zope.app() get_transaction().begin() ... get_transaction().commit() app._p_jar.close() Stefan -- The time has come to start talking about whether the emperor is as well dressed as we are supposed to think he is. /Pete McBreen/
Stefan H. Holek wrote:
--On Freitag, 11. Juli 2003 13:01 +0200 Johan Carlsson <johanc@easypublisher.com> wrote:
I guess it would look something like this?
import Globals db=Globals.DB connection=db.open() root = connection.root()
Note here that the ZODB root is *not* the Zope application object!
If you want the Zope root folder do this:
import Zope app = Zope.app() get_transaction().begin() ... get_transaction().commit() app._p_jar.close()
I can't import Zope because Zope is already started and I don't want to run the Zope __init__ magic again. Or would it be safe to import Zope from within Zope (for instance a Zope Product)? -- Johan Carlsson Tel: + 46 8 31 24 94 Colliberty Mob: + 46 70 558 25 24 Torsgatan 72 Email: johanc@easypublisher.com SE-113 37 STOCKHOLM
--On Freitag, 11. Juli 2003 15:05 +0200 Johan Carlsson <johanc@easypublisher.com> wrote:
Or would it be safe to import Zope from within Zope (for instance a Zope Product)?
It is safe. No module will be imported twice. There may be issues if you use Refresh (and Zope < 2.6.1) with your Product, but I haven't tried. Stefan -- The time has come to start talking about whether the emperor is as well dressed as we are supposed to think he is. /Pete McBreen/
Stefan H. Holek wrote:
--On Freitag, 11. Juli 2003 15:05 +0200 Johan Carlsson <johanc@easypublisher.com> wrote:
Or would it be safe to import Zope from within Zope (for instance a Zope Product)?
It is safe. No module will be imported twice.
There may be issues if you use Refresh (and Zope < 2.6.1) with your Product, but I haven't tried.
Stefan
Quite right. Thanks Stefan! After a short failure and a second test I got my Stupid-LoadZope product to work. This is surely a easier way to load the app. It also proves for me that writting from a seperate thread shouldn't be any problems. LoadZope.__init__.py: import ThreadedAsync def do_it(map): import Zope app=Zope.app() get_transaction().begin() app.title='Dude it works just fine.' get_transaction().commit() app._p_jar.close() del app ThreadedAsync.register_loop_callback(do_it) The ThreadedAsync is needed because Zope.app isn't available until Zope has started (I'm not sure why but it just wasn't there). -- Johan Carlsson Tel: + 46 8 31 24 94 Colliberty Mob: + 46 70 558 25 24 Torsgatan 72 Email: johanc@easypublisher.com SE-113 37 STOCKHOLM
Johan Carlsson wrote:
I guess it would look something like this?
import Globals db=Globals.DB connection=db.open() root = connection.root()
Another thing I been thinking about is how to get to the Applications object? If I understand it correctly the root returned by connection.root() is the root of the database, which isn't the root Application object that is shown in the Zope site hieracy? (OFS.Application.Application) So to get the application object I need to: app=root.get('Application', None) Is this correct? For the Xron product I have found this, which might be a better way to access the Application object?: app=ZODB.ZApplication.ZApplicationWrapper( DB, 'Application', OFS.Application.Application, (), Globals.VersionNameName) -- Johan Carlsson Tel: + 46 8 31 24 94 Colliberty Mob: + 46 70 558 25 24 Torsgatan 72 Email: johanc@easypublisher.com SE-113 37 STOCKHOLM
Johan Carlsson wrote:
Johan Carlsson wrote:
For the Xron product I have found this, which might be a better way to access the Application object?:
app=ZODB.ZApplication.ZApplicationWrapper( DB, 'Application', OFS.Application.Application, (), Globals.VersionNameName)
Note also that the Zron product uses AccessControl.SecurityManagement.newSecurityManager to log on as system user before creating the app object: # "Log on" as system user AccessControl.SecurityManagement.newSecurityManager(None, AccessControl.User.system) # Set up the "application" object that automagically opens # connections app=ZODB.ZApplication.ZApplicationWrapper( DB, 'Application', OFS.Application.Application, (), Globals.VersionNameName) # "Log off" as system user AccessControl.SecurityManagement.noSecurityManager() -- Johan Carlsson Tel: + 46 8 31 24 94 Colliberty Mob: + 46 70 558 25 24 Torsgatan 72 Email: johanc@easypublisher.com SE-113 37 STOCKHOLM
participants (2)
-
Johan Carlsson -
Stefan H. Holek