[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [cgiapp] Re: Preview Release available with callbacks code integrated


On Tue, 21 Dec 2004 01:03:31 +0000 (UTC), Mark Stosberg
<suppressed> wrote:
> On 2004-12-20, Cees Hek <suppressed> wrote:
> >
> > The problem comes when two developers want to run two different things
> > at the same stage.  Using the sub-classing technique works fine when
> > working on a project by yourself, but we are trying to solve a problem
> > for people that want to distribute modules (or plugins) for others to
> > use.
> 
> I think it would be useful to show a complete example. As I've thought
> through it more, I think I've re-confused myself about how it would work.

:)  I'll try to un-muddy things as much as I can.

> At what stage in the process do callbacks get registered? It seems

callbacks can be registered at any time during the execution of the
application, up until the point that the stage you are registering to
is about to be executed.  This means that a teardown callback could be
registered in the postrun stage if you wanted.  But a prerun callback
could not be registered from within a runmode, since the prerun stage
has already finished.  In my original patch there was a check for this
to make sure you were registering something that was still going to be
executed.

> obvious that they must be registered before they called. So when would
> you have a chance to register one that would run in cgiapp_init?
> 
> After you have called new(), it's too late.

Yes, this came up in the discussion at one point (many months ago). 
The user would be able to register something at the cgiapp_init stage
right after the new(), but I don't think that is very useful (since
they could just as well run any code they need right there instead of
registering it at the init stage).

So the init stage is not very usable with regards to callbacks, since
it runs so early in the process that nothing has time to register
anything at the init phase.  The reason I put the init phase in there
was more for completeness sake than anything else.  It felt cleaner to
me to include all hooks.  There were also questions as to why the
'setup' phase was not included.  I left it out, because traditionally
it is not considered a hook, but a requirement for the runmode module
to implement.

> Would plug-in users be adding code like this to cgiapp_init?

That is probably the most useful stage to register callbacks, since
this is where most of the configuration for plugins is happening (at
least for the plugins that I have developed).

>   $self->add_callback('prerun', \&callback);
> 
> If you have to explicitly add the callbacks to your code (as a
> plugin-user), it seems like it defeats the point, since you could just
> call the callback method directly at that point.

No, I think the plugin would register it directly.  Lets use a
database plugin as an example.  Here is some pseudocode for a DB
plugin method that includes a cleanup method:

sub db {
  my $self = shift;

  if (!$self->{__DB_PLUGIN}) {
    # Create new database connection
    $self->{__DB_PLUGIN} = DBI->connect(...);
    # make sure we clean up after the app is finished
    $self->add_callback('teardown', \&cleanup_db, 'LAST');
  }
  return $self->{__DB_PLUGIN};
}

sub cleanup_db {
  my $self= shift;

  if ($self->{__DB_PLUGIN}) {
    # Create new database connection
    $self->{__DB_PLUGIN}->rollback 
      unless $self->{__DB_PLUGIN}->{AutoCommit};
    $self->{__DB_PLUGIN}->disconnect;
  }
}

So this cleanup method is not registered unless the code calls
$self->db at some point.

Here is another example.  I am still planning on finishing my 'auth'
plugin at some point, and it will need to run some code at the prerun
stage.  I expect this to be done when the user configures the 'auth'
plugin.  The user will be expected to add something like this to their
code:

sub cgiapp_init {
  $self = shift;
  $self->auth_config(
                         param1 => 'value1',
                         param2 => 'value2',
                         etc...
  );
}

the auth_config method will then register a bit of code to run at the
prerun stage:

package CAP::Auth;

sub auth_config {
  my $self = shift;

  # check config options
   ...
   # register code to run at prerun stage
    $self->add_callback('prerun', \&handle_auth, 'FIRST');
}

sub handle_auth { }

Here is another possibility (this is totally untested and may not
work, but it popped into my head as I was coming up with uses for the
callbacks system).

Lets say a user has a runmode that needs to do some work that is going
to take a long time.  Why not do the work at the teardown stage after
the data has been sent to the browser:

sub my_runmode {
  my $self = shift;

  my $timeconsuming = sub {
    # close STDOUT so that the browser knows we will send no more data 
    # (not sure if this will work!!!)
    close STDOUT;
    # This is going to take a while
    sleep 600;
  };
  $self->add_callback('teardown', $timeconsuming);

  return "<html><body><h1>Task running in the background</h1></body></html>\n";
}

The page should load immediately, but the code will run on in the background.

> I'm sorry I'm muddled about this-- yesterday I thought I knew exactly
> what I was getting into. :)

So, there are three examples that each take a different approach to
using the callback mechanism.  I'm sure once it is out there other
programmers will find other ways to use it (and seeing as this is
perl, they will probably do it in some brilliantly perverse way ;)

Cheers,

-- 
Cees Hek

---------------------------------------------------------------------
Web Archive:  http://www.mail-archive.com/suppressed/
              http://marc.theaimsgroup.com/?l=cgiapp&r=1&w=2
To unsubscribe, e-mail: suppressed
For additional commands, e-mail: suppressed


Mail converted by mhonarc 2.6.15
This archive provided courtesy of JSW4.NET, Internet Hosting Services for Small Business.