Catalyst::Plugin::Continuation - Catalyst Continuation Plugin


Catalyst-Plugin-Continuation documentation Contained in the Catalyst-Plugin-Continuation distribution.

Index


Code Index:

NAME

Top

Catalyst::Plugin::Continuation - Catalyst Continuation Plugin

SYNOPSIS

Top

    # Make sure to load session plugins too!
    package MyApp;
    use Catalyst qw/Session Session::Store::File
      Session::State::Cookie Continuation/;

    # Create a controller
    package MyApp::Controller::Test;
    use base 'Catalyst::Controller';

    # Add a action with attached action class
    sub counter : Global {
        my ( $self, $c ) = @_;
        my $up      = $c->continue('up');
        my $down    = $c->continue('down');
        my $counter = $c->stash->{counter} || 0;
        $c->res->body(<<"EOF");
    Counter: $counter<br/>
    <a href="$up">++</a>
    <a href="$down">--</a>
    EOF
    }

    # Add private actions for continuations
    sub up   : Private { $_[1]->stash->{counter}++ }
    sub down : Private { $_[1]->stash->{counter}-- }

DESCRIPTION

Top

Catalyst Continuation Plugin.

OVERLOADED METHODS

Top

prepare_action

dispatch

These methods are overridden to allow the special continuation dispatch.

METHODS

Top

continuation

Contains the continuation object that was restored.

set_continuation $id, $structure

get_continuation $id

delete_continuation $id

active_continuations

clear_continuations

generate_continuation_id

These are internal methods which you can override.

They default to storing inside $c->session, and using generate_session_id in Catalyst::Plugin::Session.

If you want your continuations to be garbage collected in some way you need to override this to store the data in some other backend.

Note that active_continuations returns a hash reference which you can edit. Be careful.

$c->continuation_expired( $id )

This handler is called when the continuation with the ID $id tried to get invoked but did not exist

$c->resume_continuation( $cont_or_id );

Resume a continuation based on an ID or an object.

This is a convenience method intended on saving you the need to load and execute the continuation yourself.

$c->continue($method)

$c->cont($method)

Returns the Catalyst::Continuation object for given method.

Takes the same arguments as forward in Catalyst and it's relatives.

$c->caller_continuation

A pseudo-cc - a continuation to your caller.

Note that this does NOT honor the call stack in any way - it is ONLY to reinvoke the immediate caller. See the NeedsLogin test controller in the test suite for an example of how to use this effectively.

$c->cont_class

Returns the string Catalyst::Continuation by default. You may override this to replace the continuation class.

CAVEATS

Top

Continuations take up space, and are by default stored in the session.

When invoked a session will delete itself by default, but anything else will leak, until the session expires.

If this is a concern for you, override the get_continuation family of functions to have a better scheme for storage.

Some approaches you could implement, depending on how you use continuations:

size limiting

Store up to $x continuations, and toss out old ones once this starts to overflow. This is essentially an LRU policy.

continuation grouping

Group all the continuations saved in a single request together. When one of them is deleted, all the rest go with it.

use the fine grained session expiry feature

Catalyst::Plugin::Session allows you to expire some session keys before the entire session expired. You can associate each session with it's own unique key, and avoid extending the continuation's time-to-live.

If you override all these functions then you don't need the Catalyst::Plugin::Session dependency.

SEE ALSO

Top

Catalyst, Seaside (http://www.seaside.st/), Jifty, Coro::Cont, psychiatrist(1).

AUTHOR

Top

Sebastian Riedel, sri@oook.de Yuval Kogman, nothingmuch@woobling.org

LICENSE

Top

This library is free software, you can redistribute it and/or modify it under the same terms as Perl itself.


Catalyst-Plugin-Continuation documentation Contained in the Catalyst-Plugin-Continuation distribution.
package Catalyst::Plugin::Continuation;

use strict;
use warnings;

use Catalyst::Continuation;
use NEXT;

use base qw/Class::Accessor/;

__PACKAGE__->mk_accessors(qw/continuation/);

our $VERSION = '0.01';

*continue = \&cont;

sub get_continuation {
    my ( $c, $id ) = @_;
    $c->session->{_continuations}{$id};
}

sub set_continuation {
    my ( $c, $id, $value ) = @_;
    $c->session->{_continuations}{$id} = $value;
}

sub delete_continuation {
    my ( $c, $id ) = @_;
    delete $c->session->{_continuations}{$id};
}

sub active_continuations {
    my $c = shift;
    return $c->session->{_continuations};
}

sub clear_continuations {
    my $c = shift;
    %{ $c->session->{_continuations} } = ();
}

sub generate_continuation_id {
    my $c = shift;
    $c->generate_session_id;
}

sub prepare_action {
    my $c = shift;
    if ( $c->req->path eq "" and my $k = $c->req->params->{_k} ) {
        $c->log->debug(qq/Found continuation "$k"/) if $c->debug;
        if ( my $cont = $c->cont_class->new_from_store( $c, $k ) ) {
            $c->log->debug(qq/Restored continuation "$k"/) if $c->debug;
            $c->continuation($cont);
        } else {
            $c->continuation_expired($k);
        }
    } else {
        $c->NEXT::prepare_action(@_);
    }
}

sub dispatch {
    my $c = shift;

    if ( my $cont = $c->continuation ) {
        return $cont->execute;
    } else {
        return $c->NEXT::dispatch(@_);
    }
}

sub continuation_expired {
    my ( $c, $k ) = @_;
    die "The continuation has expired";
}

sub resume_continuation {
    my ( $c, $id_or_cont, @args ) = @_;

    (
        Scalar::Util::blessed($id_or_cont)
        ? $id_or_cont
        : $c->cont_class->new_from_store( $c, $id_or_cont )
          || $c->continuation_expired($id_or_cont)
    )->execute(@args);
}

sub cont {
    my ( $c, @args ) = @_;
    $c->cont_class->new( c => $c, forward => \@args );
}

sub caller_continuation {
    my $c      = shift;
    my $caller = $c->stack->[-2] or die "No caller";

    $c->cont_class->new(
        c                 => $c,
        forward           => [ "/" . $caller->reverse ],
        forward_to_caller => 0,
    );
}

sub cont_class { "Catalyst::Continuation" }

sub _uri_to_cont {
    my ( $c, $cont ) = @_;
    $c->uri_for( "/", { _k => $cont->id } );
}

1;