NAME

Process - Objects that represent generic computational processes

SYNOPSIS

# Create the process
my $object = MyProcess->new( ... )
    or die("Invalid configuration format");

# Initialize it
$object->prepare
    or die("Configuration not supportable");

# Execute the process
$object->run
    or die("Error while trying to execute the process");

DESCRIPTION

There are a great number of situations in which you may want to model a computational process as an object.

An implementation of this sort of object generally looks like the following when somebody uses it.

my $object = MyProcessThingy->new( ... );

my $rv = $object->run;

if ( $rv ) {
    print "Thingy ran ok";
} else {
    print "Failed to run thingy";
}

The Process family of modules are intended to be used as base and role classes for these types of objects. They are used to help identify process objects, and enforce a common API on these objects.

The primary intent is to provide a common base for objects that will be able to be used with various distributed processing systems, without itself actually implementing any form of distributed system.

The scope of uses for Process includes solutions to address the following scenarios.

A single CPU on a single host
Multiple CPUs on a single host
Multiple hosts on a single network
Hosts distributed across the internet
Any processing resource accessible via any mechanism

To put it another way, this family of classes is intended to addresses the separation of concerns between the processing of something, and the results of something.

The actual ways in which the processes are run, and the handling of the results of the process are outside the scope of these classes.

The Process class itself is the root of all of these classes. In fact, it is so abstract that it contains no functionality at all, and serves primarily to indicate that an object obeys the general rules of a Process class.

Most of the basic Process modules are similar. They define how your object should behave (an API for a particular concept) without dictating a particular implementation.

However, by using them, you are confirming to some processing system that your objects will obey particular rules, and thus can interact sanely with any processing system that follows the API.

What You Can and Cannot Do

The use of Process is mainly about making guarantees. Because this is Perl, it is not necesarily about enforcing those guarantees in a strict way. These sorts of guarantees need to be implemented at a language level to be meaningful in any case (for example, Perl's tainting or Haskell's monads). You may still hang yourself, but it's your own fault if you do.

You may not alter the API of the three core methods

It's always tempting to say "This acts like Foo, but we added an extra return condition for method bar". You may not do this.

Process and a few other members of the family dictate all possible return values for new, prepare and run, and what state the objects should be in before and after these methods are called in the various cases. You may not break these rules, because larger systems will be depending on them to allow your objects to work with them flexibly and flawlessly.

You may not store data in the surrounding Perl environment

A Process object should be entirely self-contained when you are told to be. If your process is involved in creating or transforming information, then your implementation should keep these results inside the Process object. Do not store data elsewhere. This means no globals and no class-level variables. You can't leave error messages in a global $errstr variable, as some Perl modules do.

This does not mean you can't store data in files. For Process objects that generate vast quantities of data it would be unwieldy to limit you to holding all data in memory at once. However any object data that refers to files should use absolute paths.

You may not assume the timing of new and prepare.

Most uses of Process will involve scheduling, transport, or otherwise mean that once a processing system has a Process object, it won't get to it immediately.

You should not assume that prepare will be run immediately after new or in the same interpretor. You may however assume that run is run immediately after prepare, and is in the same interpreter.

You may not assume an object is unchanged after run

A Process object may be unchanged after run. Then again, it may also be completely changed, and have accumulated all sorts of data in it.

This also means that you should not assume that a Process object can be run again after it completes. A specific class Process::Repeatable will be provided at a later date for this case.

You may not interrelate with other Process objects

In the default case, all Process objects are considered to be independent and standalone. They may not have any form of dependency on other Process objects, and they should not expect to communicate with any other Process objects.

If you choose to add this type of functionality to your particular class that is fine, but any processing system will not be aware of this and thus will not be doing anything to help you out.

Process::Depends will be provided at a later date for this case.

METHODS

new

my $object = MyClass->new( $configuration );
if ( $object and $object->isa('Process') ) {
	print "Object created.\n";
} else {
	print "Configuration not valid.\n";
}

The new constructor is required for all classes. It takes zero or more arbitrary params, with the specifics of any params outside the scope of this module. The specifics of any params are to be determined by each specific class.

A default implementation which ignores any params and creates an empty object of a HASH type is provided as a convenience. However it should not be assumed that all objects will be a HASH type.

For objects that subclass only the base Process class, and are not also subclasses of things like Process::Storable, the param-checking done in new should be thorough and and objects should be correct, with problems at run-time the exception rather than the rule.

Returns a new Process object on success.

For blame-free "Cannot support process in this Perl interpreter" failure, return false.

For failure with blame, may return a string or any other value that is not itself a Process object.

However, if you need to communicate failure, you should consider putting your param-checking in a prepare method and attaching the failure messages to the object itself. You should NEVER store errors in the class, as all Process classes are forbidden to use class-level data storage.

prepare

  unless ( $object->prepare ) {
  	# Failed
  	die "Failed to prepare process";
  }
	

The prepare method is used to check object params and bind platform resources.

The concept of object creation in new is separated from the concept of checking and binding to support storage and transportation in some subclasses.

Because many systems that make use of Process do so through the desire to push process requests across a network and have them executed on a remote host, Process provides the prepare method as a means to separate the checking of the params for general correctness from checking of params relative to the system and interpreter the process is being run on. It additionally provides a good way to have the bulk of serious errors remain attached to the object, and have them transported back across to the requesting entity.

Execution platforms are required to call run immediately or nearly immediately after prepare. Generally the only tasks done between prepare and run will be things like starting timers, setting flags and signalling to any requestor that the process is ok, and about to start.

As a result you are encouraged to do all locking of files, socket ports, database handles and so on in prepare, as they will be used immediately. Thus the only execution errors coming from run should be due to unexpected changes, race-condition events in the short gap between prepare and run, or some error that could not possibly be detected until part way through the run.

To restate, resource binding and checking should be done in prepare if at all possible.

A default null implementation is provided for you which does nothing and returns true.

Returns true if all params check out ok, and all system resources needed for the execution are bound correctly.

Returns false if not, with any errors to be propagated via storage in the object itself, for example in a ->{errstr} attribute.

The object should not return errors via exceptions. If you expect something within your code to potentially result in an exception, you should trap the exception and return false.

You should not expect the object to be Storable or in any other way usable once the Process object is prepare'ed. The object is wound up and poised ready to run and that is the only thing you should do with it.

run

my $rv = $object->run;
if ( $rv ) {
	print "Process completed successfully\n";
} else {
	print "Process interupted, or unexpected error\n";
}

The run method is used to execute the process. It should do all appropriate processing and calculation and detach from all relevant resources before returning.

If your process has any results, they should be stored inside the Process object itself, and retrieved via an additional method of your choice after the run call.

A default implementation which does nothing and returns true is provided.

Returns true if the Process was completed fully, regardless of any results from the process.

Returns false if the process was interrupted, or an unexpected error occurs. In the default case for Process, no distinction is made between the process being interrupted legitimately and any other type of unexpected failure.

If the process returns false, it should not be assumed that the process can be restarted or rerun. It should be discarded or returned to the requestor to check for specific errors.

SUPPORT

Bugs should be reported via the CPAN bug tracker at

http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Process

For other issues, contact the author.

AUTHOR

Adam Kennedy <adamk@cpan.org>, http://ali.as/

COPYRIGHT

Copyright 2006 Adam Kennedy.

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

The full text of the license can be found in the LICENSE file included with this module.