[Zope-dev] Running methods on Zope startup.

Chris McDonough chrism@zope.com
Thu, 25 Apr 2002 00:57:28 -0400


Something like this is slated for Zope 2.6.  If possible (and that's a big
if at the moment, with the work we've got lined up), it is my intention to
create a service which does the following:

- Searches for an appropriately-named on-disk directory (var/startup
probably).

- Iterates over the contents of the directory, finding all .py files and
turns them into python modules.

- Searches each module for a well-known top-level function (named "onstart"
or something similar) and calls the function with a single argument, which
will be the Zope "application" (root) object.

- The code does whatever arbitrary thing that it needs to do, using the
application object as a gateway with which it can manipulate
persistently-stored objects in the ZODB if necessary.

- Optionally, the code deletes itself (if this is a run-once sort of thing)
or places a marker in the database (or on the filesystem) that says it
should not run again at startup.

- The code finishes.

The two things that I think are different about this than what you specified
is that in my conception, the startup folder is not a persistent Zope
object, and you would need to place files in a directory on disk to hook the
startup process.  It also solves the problem of needing to have a handle to

I think your idea of registering a callback to ensure that startup is
complete before performing any actions is very sound.  I think a callback
can be registered almost anywhere, but a plausible place to create the
registration method might be in lib/python/OFS/Application.py.  Then the
callback should probably be called by lib/python/Zope/__init__.py (somewhere
after "OFS.Application.initialize(c)", after which point all Products should
be initialized).

This is a little brittle, though.  A better way to do this would be to
create a generic Zope scheduling module.  This is where hooking the asyncore
mainloop would be very appropriate.  Unfortunately, the implementation is a
bit more complex because you'd probably need to make sure the scheduler
didn't hold up the mainloop, and that means kicking off one or more threads
to do the work instead of using the main thread just at startup.  However,
it would be much more generally useful and forward-thinking to implement it
this way, even if it was a stub that didn't actually do anything but startup
stuff at first.

If I were to do this, I would:

  - Implement a stub scheduler module that was really dumb and only
    knew how to do "run once, now" jobs (no run-many jobs, no run-then
    jobs).  Do this so as to not go insane trying to reinvent cron and at
    at the moment. ;-)

  - Implement a non-Product "Startup" module that did what I explain above,
    but registered a callback with the scheduler instead of with
    the method called by Zope/__init__.

  - Change medusa's asyncore so that the "poll" (and poll2, and poll3)
    function kept track of when the scheduler had last been run.

  - In asyncore, when either the select call times out or the last time the
    schduler was run was over "X" seconds in the past, call in to
    the scheduler, telling it to wake up, modifying the "last run" time.

  - The (dumb) scheduler would wake up and notice that it had a job and
    would kick off a thread which would call back in to the startup code.
    Then it would remove the job from its queue and go on with its life,
    which would be absolutely desolate until the next time Zope started up.

This architecture would facilitate innovations (like a *real* scheduling
facility ;-) in the future.

HTH,

- C


----- Original Message -----
From: <grahamd@dscpl.com.au>
To: <zope-dev@zope.org>
Sent: Wednesday, April 24, 2002 11:56 PM
Subject: [Zope-dev] Running methods on Zope startup.


> Is there a Zope product out there which implements a "Startup" like folder
> for Zope? That is, I want to be able to have a folder like object called
> "Startup" in the root directory, and when Zope is first started I want
> Zope to automatically make a call against the "Startup" object which could
> then in turn run methods of any user defined objects which have been added
> into the "Startup" folder to perform special processing only when Zope is
> started.
>
> Imagine a situation similar to database connections. With database
connections
> when you create it you can indicate that you want the connection
established.
> Now when Zope is restarted, those database connections will be
automatically
> restarted when Zope restarts. Although, I am not sure whether this is when
> Zope actually starts or when the next request using that database happens.
>
> Anyway, I ultimately want to be able to have a Zope product which has a
> persistent interprocess messaging connection to another process. Although
> when first added into Zope the connection can be initiated, I know of no
> way to have Zope restart that connection when it restarts. I can't rely on
> the connection only starting when someone tries to access the resource, I
> want it to happen straight away upon Zope restart.
>
> When I thought about it, I figured the most basic thing to do would be to
> have a Zope "Startup" folder as described in a known place. I could then
> stick in that folder, methods to be triggered at startup which could
startup
> the interprocess communications link for me. This seemed better than
having
> a startup mechanism specific to what I was doing as it could be used for
> other things as well.
>
> Can anyone point me to such a Zope product. I have started looking at how
> to do it myself and have some of the bits in place. The first issue is
that
> when the "initialize()" method in the product "__init__.py" file is called
> not all Zope startup has occured, so it is too early to trigger things
from
> that point. Best I could come up with there was to register a callback to
> asyncore to be called when asyncore mainloop is actually run, which is
after
> all Zope startup has been done.
>
> The next problem is getting an appropriate context to be able to start
making
> calls into Zope objects. The "initialize()" method gets a product context,
> but doesn't have public access to the application context. Is there some
way
> of accessing the Zope application context and thus root folder where you
> don't otherwise have a handle to it? Can Main.bobo_application be used?
>
> Even if the application context is obtained, is it safe to be making calls
> into Zope objects from a callback from asyncore? Is there a better way?
>
> I am very new to Zope and this is my first adventure into making a Zope
> product and thus could be totally off track. If anyone understands what
> I am trying to do and can suggest how to do it or point at something that
> does what I want, then even better.
>
> Personally I would be surprised if this hadn't already been done or even
> that there is some inbuilt way of doing it now, as it opens up all sorts
of
> interesting possibilities.
>
> Appreciated if responses are cc'd to me as well as going to the list as I
> am not a member of the list yet and am using list archives.
>
> Thanks in advance.
>
> --
> Graham Dumpleton (grahamd@dscpl.com.au)
>
>
> _______________________________________________
> Zope-Dev maillist  -  Zope-Dev@zope.org
> http://lists.zope.org/mailman/listinfo/zope-dev
> **  No cross posts or HTML encoding!  **
> (Related lists -
>  http://lists.zope.org/mailman/listinfo/zope-announce
>  http://lists.zope.org/mailman/listinfo/zope )
>