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 fornew
,prepare
andrun
, 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 theProcess
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 aProcess
object, it won't get to it immediately.You should not assume that
prepare
will be run immediately afternew
or in the same interpretor. You may however assume thatrun
is run immediately afterprepare
, and is in the same interpreter. - You may not assume an object is unchanged after
run
-
A
Process
object may be unchanged afterrun
. 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 otherProcess
objects, and they should not expect to communicate with any otherProcess
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>
SEE ALSO
COPYRIGHT
Copyright 2006 - 2009 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.