Skip to content
September 22, 2010 / Andy

Monitor Commands with POE and Moose


I really like POE and I really like Moose. It would be great if they had some kind of love child that gave me the power of POE in a modern Moosey package. Turns out there are a couple options out there:

  • MooseX::POE – I believe this was the first module that tried to combine Moose and POE. However, by the author’s own admission it may have some issues.
  • Reflex - Which is from the author of POE and seems to be regarded as the state of the art. Unfortunately, it still needs some time to cook before it’s ready for production.
  • POEx::Role::SessionInstantiation – Another evil creation from the mind of nperez (I always end up using his modules).
    Edit: In the comments section, Chris Prather pointed out that “the fatal flaws in MooseX::POE also infect POEx::Role::SessionInstantiation”.


So I went with POEx::Role::SessionInstantiation. My biggest problem with the module is that the documentation is a bit intimidating and I had a hard time putting things together. Hopefully people can use my simple example to supplement what the documentation offers.


Now, on to the example. The basic idea was to get output from a command and have that output update the state of my object. Each time the state was updated I also wanted the command to post an event that I could listen to outside of the object as it was running.

use MooseX::Declare;

class LongRunningCmd {
	with 'POEx::Role::SessionInstantiation';
	use aliased 'POEx::Role::Event';

	has wheel => (
		is     => 'rw',
		isa    => 'Maybe[POE::Wheel::Run]',
	);

	has callback => (
		is  => 'ro',
		isa => 'CodeRef',
	);

	has current_state => (
		is  => 'rw',
		isa => 'Str',
	);

	after _start is Event {
		# Use POE::Wheel::Run to run the command and properly parse it's output
		$self->wheel(
			POE::Wheel::Run->new(
				Program      => ['my', 'long', 'running', 'command'],
				StdoutEvent  => 'on_stdout',
			)			
		);

		# Use sig_child to cleanup our long running program once it exits
		$self->poe->kernel->sig_child($self->wheel->PID, 'on_signal');

		# Register an event that we will fire each time the state of this object is updated
		$self->poe->kernel->state('callback_event', $self->callback);
	}

	method on_stdout(Str $stdout, Int $wheel_id) is Event {
		# Parse stdout and use it to update the state of the object
		# This would most likely be a lot more complicated
		$self->current_state($stdout);

		# Post a the 'callback_event' because the object state has changed
		$self->post($self, 'callback_event') if ($self->callback);
	}

	method on_signal(Str $chld, Int $pid, Int $exit_val) is Event {
		# Set the wheel to undef so that ->run() can finish.
		$self->wheel(undef);
	}
}

my $long_running_cmd = LongRunningCmd->new(
	# Pass in a sub so that the progress can be monitored as the object runs.
	callback => sub {
		my $callback_test = shift;

		say $callback_test->current_state;
	}
);

POE::Kernel->run();


As always I welcome feedback. In particular I’m wondering if there are better ways than using a CodeRef for callbacks.

About these ads

4 Comments

Leave a Comment
  1. Matt S Trout / Sep 22 2010 11:25 AM


    use IPC::Command::Multiplex;

    multiplex(
    run => [ \@command ],
    callback => sub {
    chomp(my $line = shift);
    say $line;
    }
    );

    • Andy / Sep 22 2010 12:52 PM

      Thanks mst, it’s good to know that I’m not the only one using a CodeRef as a callback.

  2. Chris Prather / Sep 23 2010 7:09 AM

    Mind you from what Nick says the fatal flaws in MooseX::POE also infect POEx::Role::SessionInstantiation. Namely that there is a 1:1 relationship between a session and an object. Because of the natural weight of POE’s sessions this has a lower scaling limit than Reflex which uses a more modern paradigm for the message passing.

    • Andy / Sep 23 2010 9:40 AM

      Thanks Chris, I think this information is important enough that I made a small edit to the post.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: