4. Nature of Cloud Applications
Building for Uncertainty
I The Cloud is everywhere and all the time, but not reliably.
I In a one-server ("mainframe") environment we can reasonably
assume that our contact partners or services we use are always on
and accept our requests. But not in the cloud. There we have no
control over the services we use.
I We must:
1. Assume the other party cannot establish contact with us when we
need to.
2. Assume that the execution time and network speed are not constants
but depend on uncontrollable factors.
I So it follows: We cannot build tightly connected applications!
5. Solution?
I If not tightly-coupled applications then loosely-coupled!
connection No straight socket connections.
separation Strict separation of dierent functionality.
transaction One task: Complete or fail. No between.
messaging Asynchronous messages between dierent parts of the application.
I A message queue in the cloud, not tied to one server, not brokering
of messages between nodes. REST interface.
I IronMQ
6. IO::Iron
CPAN Libraries
I CPAN: IO::Iron
I Perl Libraries for IronMQ, IronCache and IronWorker
I Author: Mikko Koivunalho mikkoi@cpan.org
I https://metacpan.org/release/IO-Iron
I Uses REST::Client (LWP)
I Additional package IO::Iron::Applications contains command line
interface clients for the same services.
7. Quickstart I
I We need the access key (OAuth) from Iron.io. Save it as
8. le
'iron.json' for default setup.
I Sample iron.json:
f p r o j e c t i d : XXXXXXXXXXXXXXXXXXXXXXXX ,
token : YYYYYYYYYYYYYYYYYYYYYYYYYYY ,
ho s t : mqawseuwest 1. i r o n . i o g
9. Quickstart II
I Send a message.
us e IO : : I r o n ;
r e q u i r e IO : : I r o n : : IronMQ : : Message ;
my $mq c l i e n t = i ronmq ( ) ;
my $queue = $mq c l i e n tc r e a t e q u e u e ( ' name ' = ' TestQueue ' ) ;
my $msg = IO : : I r o n : : IronMQ : : Messagenew( ' body ' = Tes t
mes sage ) ;
my $msg id = $queuepush ( ' mes sages ' = [ $msg ] ) ;
10. Quickstart III
I Receive messages.
us e IO : : I r o n ;
r e q u i r e IO : : I r o n : : IronMQ : : Message ;
my $mq c l i e n t = i ronmq ( ) ;
my $queue = $mq c l i e n tc r e a t e q u e u e ( ' name ' = ' TestQueue ' ) ;
my @msgs = $queuep u l l ( ' n ' = 1 , ' t imeout ' = 1 ) ;
f o r e a c h my $msg (@msgs ) f
p r i n t $msgbody ( ) ;
g
11. IO::Iron::IronMQ Interface
I Divided into two parts:
I Operations on queues (handled via package IronMQ::Client)
$ i r o nmq c l i e n t c r e a t e q u e u e ( name = ' ' )
$ i r o nmq c l i e n t g e t q u eu e ( name = ' ' )
$ i r o nmq c l i e n t upda t e queue ( name = ' ' , )
$ i r o nmq c l i e n t d e l e t e q u e u e ( name = ' ' )
$ i r o nmq c l i e n t g e t i n f o a b o u t q u e u e ( name = ' ' )
$ i r o nmq c l i e n t g e t q u e u e s ( )
I Operations on messages (handled via package IronMQ::Queue)
$queuepush ( ' mes sages ' = [ $msg ] ) ;
$queuep u l l ( n = 10 , t imeout = 120 ) ;
$queuepeek ( n = 10 ) ;
$queued e l e t e ( ' i d s ' = [ $msg id ] ) ;
$queuer e l e a s e ( ' i d ' = $msg id , ' d e l a y ' = $ d e l a y ) ;
$queuetouch ( ' i d ' = $msg id ) ;
$queuec l e a r ( ) ;
$queues i z e ( ) ;
12. IronMQ::Queue
I IO::Iron::IronMQ::Queue objects are created by the client
IO::Iron::IronMQ::Client.
I With an IO::Iron::IronMQ::Queue object you can push messages to
the queue, or pull messages from it.
I The names push and pull are used because the queue is likened to a
pipe. The queue is like a FIFO pipe (
14. rst out).
I Operations are atomic and messages will be read in the same order
as they were sent.
15. IronMQ::Message
I A message (an object of class IO::Iron::IronMQ::Message) will
contain the following parameters:
body Free text string. Serialized object (JSONized).
timeout When reading from queue, after timeout (in seconds), item will be
placed back onto queue.
delay The item will not be available on the queue until this amount of
seconds have passed.
expires in How long in seconds to keep the item on the queue before it is
deleted. Useful for, e.g. alarm queues.
id Message id from IronMQ (available after message has been
pulled/peeked).
r e q u i r e IO : : I r o n : : IronMQ : : Message ;
r e q u i r e JSON : : MaybeXS ;
my $ j s o n = JSON : : MaybeXSnew( u t f 8 = 1 , p r e t t y = 1) ;
my %msg body hash = ( ms g body t e x t = 'My mes sage #01 ' ,
msg body i t em = f s u b i t em = ' Sub t e x t ' g) ;
my $msg body = $j sonencode (n%msg body hash ) ;
my $msg = IO : : I r o n : : IronMQ : : Messagenew( ' body ' =$msg body ,
' t imeout ' = 60 , ' d e l a y ' = 0 , ' e x p i r e s i n ' = 60 ,
) ;
16. Push Queues I
Delivery to Front Door
I One of IronMQ's outstanding features are push queues.
I Instead of polling a message queue, you can set subscribers to a
queue.
I Subscribers are simply URL's that IronMQ will post to whenever a
message is posted to your queue. There are currently three types
subscribers supported, all dierentiated by the URL scheme (
17. rst
part of the URL):
1. HTTP endpoints: urls with the http or https pre
18. x for instance,
2. http://myapp.com/some/endpoint or
https://myapp.com/some/endpoint.
3. IronMQ endpoints: IronMQ endpoints point to another queue on
IronMQ. Use these to do fan-out to multiple queues.
4. IronWorker endpoints: IronWorker endpoints will
19. re up an
IronWorker task with the message body as the payload.
20. Push Queues II
my $push queue = $ i r o n mq c l i e n t upda t e queue (
' name ' = 'My Message Queue ' ,
' s u b s c r i b e r s ' = [
f u r l = i ronmq :/// Other queue name g ,
f u r l = ht tp : / /my . s e r v e r g ,
] ,
' p u s h t y p e ' = ' mu l t i c a s t ' ,
' r e t r i e s ' = 0 ,
' r e t r i e s d e l a y ' = 3 ,
' e r r o r q u e u e ' = Er ror queue name ,
) ;
I Get push status for a message.
my $ i n f o = $i ron mq queueg e t p u s h s t a t u s ( ' i d ' = $msg id
) ;
my @s u b s c r i b e r s = (@f i n f o f ' s u b s c r i b e r s ' gg) ;
21. Push Queues III
I Acknowledge / Delete Push Message for a Subscriber.
I This is only for use with long running processes that have previously
returned a 202 (Request accepted, processing delayed or takes a
long time).
my $push acknowl edged = $queued e l e t e p u s h me s s a g e (
' i d ' = $msg id , ' s u b s c r i b e r ' = $ s u b s c r i b e r s [0]f ' i d ' g
) ;
22. Push Queues IV
I Add Subscribers to a Queue.
my $ a d d r e t v a l = $queuea d d s u b s c r i b e r s (
' name ' = $queue name ,
' s u b s c r i b e r s ' = [
f ' u r l ' = i ronmq : / / p r o j e c t i d : token n@hos t /
queue name g ,
f ' u r l ' = i ronmq :/// $queue name 02 g ,
] ,
) ;
I Remove Subscribers from a Queue
my $ d e l r e t v a l = $ i r o n mq c l i e n t d e l e t e s u b s c r i b e r s (
' name ' = $queue name ,
' s u b s c r i b e r s ' = [
f ' u r l ' = i ronmq :/// $queue name g ,
] ,
) ;
23. Logging and Debugging
I Package IO::Iron uses Log::Any for logging.
I Every atomic action (with Iron.io remote services) and a few other
actions produce a log entry.
I Log entries can be routed to a compatible logger with
Log::Any::Adapter.
I Log::Any is also used to output logging verbose/debugging log
entries.
I Just raise the throughput level to 'debug' or 'trace'.
I Trace will output the entry and exit points of almost every functions,
together with function parameters and return values.
If you need a quick and dirty solution, try this at the beginning of a
24. le:
us e Log : : Any : : Tes t ; # s h o u l d appear b e f o r e ' us e Log : : Any ' !
us e Log : : Any qw( $ l o g ) ;
us e Log : : Any : : Adapter ( ' S t d e r r ' ) ;