Catalyst::Engine::Stomp - write message handling apps with Catalyst.
# In a server script: BEGIN { $ENV{CATALYST_ENGINE} = 'Stomp'; require Catalyst::Engine::Stomp; } MyApp->config( Engine::Stomp' = { tries_per_server => 3, 'servers' => [ { 'hostname' => 'localhost', 'port' => '61613' connect_headers => { login => 'myuser', passcode => 'mypassword', }, }, { 'hostname' => 'stomp.yourmachine.com', 'port' => '61613' }, ], utf8 => 1, subscribe_headers => { transformation => 'jms-to-json', } }, ); MyApp->run(); # In a controller, or controller base class: use base qw/ Catalyst::Controller::MessageDriven /; # then create actions, which map as message types sub testaction : Local { my ($self, $c) = @_; # Reply with a minimal response message my $response = { type => 'testaction_response' }; $c->stash->{response} = $response; }
Write a Catalyst app connected to a Stomp messagebroker, not HTTP. You need a controller that understands messaging, as well as this engine.
This is single-threaded and single process - you need to run multiple instances of this engine to get concurrency, and configure your broker to load-balance across multiple consumers of the same queue.
Controllers are mapped to Stomp queues or topics, and a controller base class is provided, Catalyst::Controller::MessageDriven, which implements YAML-serialized messages, mapping a top-level YAML "type" key to the action.
The controller namespace (either derived from its name, or defined by its action_namespace attribute) defines what the controller is subscribed to:
action_namespace
queue/foo
subscribes to the queue called foo
foo
topic/foo
subscribes to the topic called foo
subscribes to the queue called foo (for simplicity and backward compatibility)
You can specify custom headers to send with the CONNECT and SUBSCRIBE STOMP messages. You can specify them globally:
CONNECT
SUBSCRIBE
MyApp->config( Engine::Stomp' = { 'servers' => [ { 'hostname' => 'localhost', 'port' => '61613' }, ], subscribe_headers => { transformation => 'jms-to-json', }, connect_headers => { login => 'myuser', passcode => 'mypassword', }, }, );
per server:
MyApp->config( Engine::Stomp' = { 'servers' => [ { 'hostname' => 'localhost', 'port' => '61613' subscribe_headers => { strange_stuff => 'something', }, connect_headers => { login => 'myuser', passcode => 'mypassword', }, }, ], }, );
or per-controller (subscribe headers only):
package MyApp::Controller::Special; use Moose; BEGIN { extends 'Catalyst::Controller::MessageDriven' }; has stomp_destination => ( is => 'ro', isa => 'Str', default => '/topic/crowded', ); has stomp_subscribe_headers => ( is => 'ro', isa => 'HashRef', default => sub { +{ selector => q{custom_header = '1' or JMSType = 'test_foo'}, } }, );
This is very useful to set filters / selectors on the subscription.
There are a few caveats, mostly summarized by "if you do confusing things, the program may not work".
you can have the stomp_destination and the action_namespace different in a single controller, but this may become confusing if you have more than one controller subscribed to the same destination; you can remove some of the confusion by restricting the kind of messages that each subscription receives
stomp_destination
if you filter out some messages, don't be surprised if they are never received by your application
you can set persistent topic subscriptions, to prevent message loss during reconnects (the broker will remember your subscription and keep the messages while you are not connected):
MyApp->config( Engine::Stomp' = { 'servers' => [ { 'hostname' => 'localhost', 'port' => '61613' }, ], connect_headers => { 'client-id' => 'myapp', }, }, ); package MyApp::Controller::Persistent; use Moose; BEGIN { extends 'Catalyst::Controller::MessageDriven' }; has stomp_destination => ( is => 'ro', isa => 'Str', default => '/topic/important', ); has stomp_subscribe_headers => ( is => 'ro', isa => 'HashRef', default => sub { +{ 'activemq.subscriptionName' => 'important-subscription', } }, );
According to the ActiveMQ docs, the client-id must be globally unique, and activemq.subscriptionName must be unique within the client. Non-ActiveMQ brokers may use different headers to specify the subscription name.
client-id
activemq.subscriptionName
You can specify one or more servers in a list for the apps config. This enables fail over if an error occurs, like the broker or network connection disappears.
It will try to use a server a set number of times, as determined by tries_per_server in the config before failing on to the next server in the list. It cycle through each server in turn, going back to the start of the list if need be.
By default STOMP messages are assumed to be in UTF-8. This module can automatically convert a Perl string into a UTF-8 set of octets to be sent over the wire instead. This is a Good Thing, especially if you use the function Load() from the package YAML::XS to un-serialize it in your client - it assumes it is in UTF-8.
If you do want this behaviour, set 'utf8' to '1' in your config.
Instead of using the complete config layout as shown in the synopsis, you can
not specify a tries_per_server (defaults to 1)
tries_per_server
specify a single server:
server => { hostname => $host, port => $port }
use the old-style (pre 0.14) config having hostname and port directly in the Engine::Stomp block, without a server key in between.
hostname
port
Engine::Stomp
server
Set to run when signal USR1 is received. Simply sets the stop flag.
App entry point. Starts a loop listening for messages.
If the stop flag is set (see _see_ya above) then no more requests are processed. Keep in mind this is a blocking server and it will wait for a STOMP message forever. Only after handling a request does it check the flag.
Overridden to add the source broker to the request, in place of the client IP address.
Overridden to dump out any errors encountered, since you won't get a #' "debugging" message as for HTTP.
Dispatch according to Stomp frame type.
Dispatch a Stomp message into the Catalyst app.
Log any Stomp error frames we receive.
Add additional header key/value pairs to the subscribe message sent to the message broker.
The source to Catalyst::Engine::Stomp is in github:
http://github.com/pmooney/catalyst-engine-stomp
Chris Andrews <chris@nodnol.org>
<chris@nodnol.org>
Tomas Doran (t0m) <bobtfish@bobtfish.net>
<bobtfish@bobtfish.net>
Jason Tang
Paul Mooney
Copyright (C) 2009 Venda Ltd
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available.
To install Catalyst::Engine::Stomp, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Catalyst::Engine::Stomp
CPAN shell
perl -MCPAN -e shell install Catalyst::Engine::Stomp
For more information on module installation, please visit the detailed CPAN module installation guide.