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.

September 22, 2010 / Andy

I <3 the Perl Community


I’ve been messing around with Reflex recently and it’s a joy to use. So much so that I got a bit overzealous and tried using it with some of my production code. What I found is that it isn’t quite ready, though I doubt any of it’s developers would say otherwise. While tinkering with Reflex I was able to submit a couple of failing tests in #reflex on irc.perl.org. Not only did dngor respond right away confirming the tests were bugs, rather than my own misunderstanding, but he released a fix and posted the new code to CPAN within a day. The whole process reminded me why I love the Perl community. Thank you dngor.

September 2, 2010 / Andy

Introducing Catalyst::Controller::DirectoryDispatch


During Nick Perez’s Intro to Catalyst talk at YAPC::NA one of the attendees asked if there was a built in catalyst controller for listing system directories. Being the helpful individual I am, I gave some details about a controller I created that lists system directories and dispatch them as URLs. Nick asked me why I hadn’t made the code available on CPAN. It turns out I really didn’t have a good reason for him. So I present a trial release of Catalyst::Controller::DirectoryDispatch. This is my first CPAN module so I’m interested in any feedback I can get. If anyone has suggestions on code, features, tests, documentation, or anything else please let me know.

June 18, 2010 / Andy

MooseX::Daemonize and init.d


It only took me two weeks in the Iron Man competition to fail. That may actually be some kind of record. The last few weeks at $work have been pretty busy and I haven’t had the time or energy to work on blog posts. However, with YAPC::NA only a few days away and my excitement growing I decided to write up a quick post with a bit of fun I had messing with daemons.


In the past I’ve written my daemons as simple scripts. They worked reasonably well but after a couple years and even more rewrites I decided to see what CPAN had to offer. In particular I thought I’d take a look at a more moosey implementation. Turns out it’s super easy and includes all the things I needed to run it as a system service.

package MyDaemon;
use Moose;
use Try::Tiny;
use namespace::autoclean;

with qw(MooseX::Daemonize);

after start => sub {
	my $self = shift;
	return unless $self->is_daemon();
	
	while (1) {
			try {
				# Your daemon code here
			}
		}
		
		sleep(3600);
	}
};


That’s it. The MooseX::Daemonize code handles pretty much everything you’d expect a daemon to do. Next, I wanted it to be integrated as a system service. For that I had to make it runnable using MooseX::Runnable.

package MyDaemon;
use Moose;
use Try::Tiny;
use namespace::autoclean;

with qw(MooseX::Daemonize MooseX::Runnable);

sub run {
	my $self = shift;
	
	$self->start();
	
	exit(0);
}

after start => sub {
	my $self = shift;
	return unless $self->is_daemon();
	
	while (1) {
			try {
				# Your daemon code here
			}
		}
		
		sleep(3600);
	}
};


Ok, simple enough. Now the module can be run as an application using the mx-run command. On to the final step, the init.d script.

PIDFILE=/var/run/mydaemon.pid
COMMAND="mx-run -I/path/to/MyDaemon.pm"

# Source function library
. /etc/rc.d/init.d/functions


start() {
        echo -n "Starting My Daemon: "
        if [ -f $PIDFILE ]; then
                PID=`cat $PIDFILE`
                echo my daemon already running: $PID
                exit 2;
	fi

        daemon $COMMAND
	echo
}

stop() {
        echo -n "Stopping My Daemon: "

        killproc mydaemon
	echo
}

case "$1" in
  start)
	start
        ;;
  stop)
	stop
        ;;
  restart)
        stop
	start
        ;;
  status)
        status mydaemon
        ;;
  *)
        echo "Usage: {start|stop|restart|status}"
        exit 1
esac

exit 0


Now I can do service mydaemon start/stop/status/restart and the system manages the daemon for me. A simple chkconfig and it’s running at startup. Very nice.


Please be aware that I’m running CentOS 5.4 so your mileage may vary in regards to the init.d script.

June 2, 2010 / Andy

Creating Extjs TreeNodes client side


Recently I converted my back-end to a almost purely RESTful implementation. It works great and simplifies a lot but it causes a few problems as well. One of them being getting data into extjs TreePanels. To keep the API simple I no longer want to create extra controllers that formatted the data into nodes. My solution was to create the Ext.ux.CustomNodeTreeLoader.


The general idea is that you intercept the raw data from your ajax calls and then write a custom function to convert that data into nodes in your front-end.

Ext.namespace('Ext.ux');

/* Works the same as the normal tree loader but has an extra
 * config option called customLoad which expects a function.
 * The function is passed the decoded JSON responseText from
 * the nodes ajax call as well as the node itself.
 * 
 * This is handy for intercepting the ajax and creating nodes
 * based on the response. That way the backend can stay general
 * and decoupled.
 * 
 * Andy, 4/27/2010
 */
Ext.ux.CustomNodeTreeLoader = Ext.extend(Ext.tree.TreeLoader, {
	processResponse:function(response, node, callback, scope) {
	    var json = response.responseText;
	    try {
	        var o = response.responseData || Ext.decode(json);
	        
	        // Andy, call custom load if you want to construct
	        // your own nodes from raw data.
	        o = this.customLoad(o, node);
	        
	        node.beginUpdate();
	        for(var i = 0, len = o.length; i < len; i++){
	            var n = this.createNode(o[i]);
	            if(n){
	                node.appendChild(n);
	            }
	        }
	        node.endUpdate();
	        this.runCallback(callback, scope || node, [node]);
	    }catch(e){
	        this.handleFailure(response);
	    }
	},
	
	// This is the function that you need to override. Currently
	// it only gives the same functionality as Ext.tree.TreeLoader.
	customLoad:function(o, node) {
		return o;
	}
});

Ext.reg('customnodetreeloader', Ext.ux.CustomNodeTreeLoader);


Now inside your TreePanel’s loader you can use the config option customLoad.

loader:new Ext.ux.CustomNodeTreeLoader({
	dataUrl:'/acl/users',
	requestMethod:'GET',
	customLoad:function(data, node) {
		// data is the decoded response.responseText
		// node is the node that's being expanded

		var nodes = [];
		var users = data.data;
		Ext.each(users, function(user) {
			nodes.push({
				text:user.username,
				leaf:true,
				iconCls:'user_icon'
			});
		});

		return nodes;
	},
	headers:{
		'Content-Type':'application/json'
	}
})
May 28, 2010 / Andy

DBIC::API, Extjs EditorGridPanel, and mapping data from multiple database tables

I’ve recently started using the DBIC::API plugin for catalyst. It does so much right out of the box that I had a basic RESTful interface up and running in a matter of minutes. I also use extjs almost exclusively for creating my front-ends at work. The two are quite a good fit. In fact, all you need for basic CRUD is to create an extjs EditorGridPanl, give its store the restful:true config option, and point its HttpProxy at the DBIC::API URL.

Everything works great in the standard situation where the extjs grid has a one to one mapping with a database table. However, I often find myself wanting data from related tables to be included in my grids. Just populating the grid isn’t a problem. My first attempt looked something like this:

store:new Ext.data.Store({
	proxy:new Ext.data.HttpProxy({
		url:'/rest/person?prefetch=["address"]',
		restful:true,				
		reader:new Ext.data.JsonReader({
    			totalProperty:'totalcount',
    			successProperty:'success',
    			idProperty:'person_id',
    			root:'data',
    			messageProperty:'message'  // <-- New "messageProperty" meta-data
		},[
			{name:'person_id',  type:'int'},
		   	{name:'first_name', type:'int'},
		   	{name:'last_name',  type:'int'},
		   	{name:'address'}    // Object
		])
	)}
)}

The HttpProxy calls the URL /rest/person?prefetch=["address"]. This tells DBIC::API to return a list of people in the database with each person including the related address information. After the call the address information is available in the grids store as an object. So far so good.

The problem arises when you add a writer to you store so you can create and update data in the grid. DBIC::API doesn’t prefetch when doing a POST or PUT operation. That means, after an update or create, related rows aren’t returned causing the grids to lose any of that related information we’re relying on. To solve the problem just override the following functions in your class that extends Catalyst::Controller::DBIC::API::REST.

package MyApp::BaseController::DBIC::API::REST;
use Moose;
BEGIN {extends 'Catalyst::Controller::DBIC::API::REST'; }

sub update_or_create {
	my ($self, $c) = @_;
	
	$self->next::method($c);
	
	# Get the newly created/updated object's primary key
	# Here we assume that the object has just 1 primary key.
	# This is possibly a limitation of DBIC::API anyway.
	my $pk = [$c->req->current_result_set->result_source->primary_columns]->[0];

	# Get the objects from the request context then clear the request context	
	my $objects = [$c->req->all_objects];
	$c->req->clear_objects();
	
	# Lookup each created/updated object using the passed in search_attributes.
	# This could cause up to n extra mysql calls where n is the number of created/updated
	# rows.
	$c->req->add_object([$self->object_lookup($c, $_->$pk), {}]) for map { $_->[0] } @$objects;
}

sub object_lookup
{
    my ($self, $c, $id) = @_;

    die 'No valid ID provided for look up' unless defined $id and length $id;
    
    # Make sure that objects use the passed in search attributes.
    # Most importantly the prefetch attribute.
    my $object = $c->req->current_result_set->find($id,
       	$c->req->search_attributes
    );
        
    die "No object found for id '$id'" unless defined $object;
    
    return $object;
}

sub each_object_inflate
{
    my ($self, $c, $object) = @_;
   
	my $hash = $self->next::method($c, $object);

	# Inflate the prefetched rows as well and add them into our hash
    foreach my $related ( @{$c->req->search_attributes->{prefetch}} ) {
    	next unless defined ($object->$related);
    	
    	# If a has_many is encountered then get it's rows but go no further.
    	if ($object->$related->isa('DBIx::Class::ResultSet')) {
    		push(@{$hash->{$related}}, { $_->get_columns }) for ($object->$related->all);
    	}
    	else {
    		$hash->{$related} = { $object->$related->get_columns };
    	}
    }
    
    return $hash;
}

1;

These overrides make it so search attributes, like prefetch are honored in POST and PUT requests. Once a new row has been created or updated, instead of just returning the row, DBIC::API now does another query with the given search options. This makes extjs happy because now it has the full set of data that it expects.

To make this really work one more override is required. This time on the extjs side. Inside your HttpProxy is a property called api. It allows you to specify the URL and method for each action (read/update/create/destroy). Unfortunately it doesn’t allow the specification of params for each call. Here is an override to change that.

/* Allows the use of params inside the api config option of
 * Ext.data.HttpProxy.
 * 
 * This is handy when extra params need to be sent to the
 * controller (prefetch for example).
 */

Ext.override(Ext.data.HttpProxy, {
    doRequest : function(action, rs, params, reader, cb, scope, arg) {
	    var  o = {
	        method: (this.api[action]) ? this.api[action]['method'] : undefined,
	        request: {
	            callback : cb,
	            scope : scope,
	            arg : arg
	        },
	        reader: reader,
	        callback : this.createCallback(action, rs),
	        scope: this
	    };
	
	    // If possible, transmit data using jsonData || xmlData on Ext.Ajax.request (An installed DataWriter would have written it there.).
	    // Use std HTTP params otherwise.
	    if (params.jsonData) {
	        o.jsonData = params.jsonData;
	        // Edit, make use if api params if they exist
	        Ext.applyIf(o.jsonData, this.api[action].params);
	    } else if (params.xmlData) {
	        o.xmlData = params.xmlData;
	        // Edit, make use if api params if they exist
	        Ext.applyIf(o.xmlData, this.api[action].params);
	    } else {
	        o.params = params || {};
	        // Edit, make use if api params if they exist
	        for (var param in this.api[action].params) {
	        	o.params[param] = Ext.encode(this.api[action].params[param]);
	        }
	    }
	    // Set the connection url.  If this.conn.url is not null here,
	    // the user must have overridden the url during a beforewrite/beforeload event-handler.
	    // this.conn.url is nullified after each request.
	    this.conn.url = this.buildUrl(action, rs);
	
	    if(this.useAjax){
	
	        Ext.applyIf(o, this.conn);
	
	        // If a currently running request is found for this action, abort it.
	        if (this.activeRequest[action]) {
	            ////
	            // Disabled aborting activeRequest while implementing REST.  activeRequest[action] will have to become an array
	            // TODO ideas anyone?
	            //
	            //Ext.Ajax.abort(this.activeRequest[action]);
	        }
	        this.activeRequest[action] = Ext.Ajax.request(o);
	    }else{
	        this.conn.request(o);
	    }
	    // request is sent, nullify the connection url in preparation for the next request
	    this.conn.url = null;
	}
});

With that taken care of we can now change our HttpProxy to use the new params config.

store:new Ext.data.Store({
	proxy:new Ext.data.HttpProxy({
		url:'/rest/person',
		restful:true,
		api:{
			read:{
				url:'/rest/person',
				params:{
					prefetch:["address']
				}
			},
			create:{
				url:'/rest/person',
				params:{
					prefetch:["address']
				}
			},
			update:{
				url:'/rest/person',
				params:{
					prefetch:["address']
				}
			}
		},			
		reader:new Ext.data.JsonReader({
    			totalProperty:'totalcount',
    			successProperty:'success',
    			idProperty:'person_id',
    			root:'data',
    			messageProperty:'message'  // <-- New "messageProperty" meta-data
		},[
			{name:'person_id',  type:'int'},
		   	{name:'first_name', type:'int'},
		   	{name:'last_name',  type:'int'},
		   	{name:'address'}    // Object
		])
		...
	)}
)}

That’s all there is to it. You can now prefetch in POST and PUT requests.

I know some of this code is quite messy. I’m still getting the hang of how a lot of this stuff works. Feedback of any kind is welcome.

May 28, 2010 / Andy

Fear and Loathing in Columbus


Because this is my first blog post in a few years I think a few words are in order. I’ve been finding myself having a lot of fun programming in Perl lately. This is mostly because of my discovery of catalyst and moose, which are a pleasure to work with. It also has a good deal to do with the community at large. I stumbled onto Iron Man competition and decided to dust off the old blog. This post is only loosely related to Perl but for me it’s an important topic.


I’m heading to YAPC::NA in Ohio next month. As usual when I do these sorts of things, my emotions are a mixed bag. Excitement is a key component, certainly. Though, my old friend anxiety is creeping in as well. I’ve lived with social anxiety in one form or the other for most of my life. It can be a tough problem to confront. Rationally I realize that most of the people attending the conference are going to be friendly and excited to socialize. Unfortunately, my emotional side, the side that tells me I should be worried, doesn’t give a shit about what’s rational. Historically, this has led me to go into these things with the mindset that I just have to buckle down and get through it. This, as you might imagine, causes me to sit by myself and not talk to anyone. Even though that sounds like a blast, let me assure you that it isn’t all that satisfying.


Alright, that was depressing, now for the good stuff. This last year I’ve been working on my anxiety and it’s led me, at least in part, to start treating these trips differently. I now see them as a way to challenge myself to engage others socially. It turns out the topic of conversation really doesn’t matter. The point is to challenge the way I see myself. Specifically, the idea that no one cares about a damn thing I have to say. It ends up working out quite nicely. So much so that during my last trip I ended up talking to a lot of people and in the process had a great time. Not to say that it was easy for me. It certainly wasn’t. But it did get easier the longer I kept at it.


I’m writing this out in part so that I’ll feel obligated to follow through at YAPC::NA, which on one hand is a good thing but on the other it’s scary as hell. My other reason is to increase awareness of the condition. I’m fairly new to the Perl community but writing open source software is inherently altruistic and I get the feeling the community carries those ideals into their everyday lives (contrary to one might see on IRC). So if you notice anyone sitting by themselves not engaging with others then I encourage you to strike up a conversation. Especially if you’re one of those people that usually sits by yourself not engaging.

Follow

Get every new post delivered to your Inbox.