IO::Iron - Towards Update

A string of new releases for package IO::Iron libraries is coming soon. The main reason for this are the changes in Iron.io's new v3 IronMQ but I'm also using this chance to correct some problems or (misunderstood) features in the Perl Client Library API.

IronMQ v3

In 2015 Iron.io released a new version of their IronMQ services, the version 3. The previous version was v2.0.1 althought it was using the version prefix '/1' in url addresses, e.g. 'https://mq-aws-us-east-1.iron.io/1/projects/{Project ID}/queues'.

IronMQ v3 API has only a few big differences compared with v2:

Dequeue now returns a reservation. This reservation_id and message_id are required to perform any action (ie deleting, touching, releasing). The reservation is valid for the length of the message timeout (inherited from the queues timeout) unless a timeout was specified on the dequeue call.

Expiration and timeout can no longer be set on message enqueue.

Push queues must be explicitly created. There's no changing a queue's type.

Can no longer set timeout when posting a message, only when reserving one.

Whole list of Changes in Iron.io's v3 API Reference.

The biggest of these changes is the workflow change. V2 has 'post-get-delete', v3 has 'post-reserve-delete'. 'Get Messages' is no longer available, though 'Get Message by Id' still is. So you can ask for a particular message if you know its id number. The 'Peek Messages' command is again available. It was deprecated from the v1/v2 API (though still available). 'Reserve Messages' does the same as 'Get Messages' earlier but underlines that it is indeed reserving the messages exclusively for the caller. You can reserve max 100 messages at one go. The optional parameter 'delete' is still present (to delete the messages right away, if you are sure it won't matter even if it doesn't get processed). 'Reserve Messages' returns a reservation id which will be used to delete the message from queue after processing it securely. Deleting a message is not possible without a reservation id. In v2 you only needed the message id to delete it.

Changes in Perl Client Library

API Changes

The main problem I have now is how to support the IronMQ v3. The two alternatives are:

branch: Create a separate branch, i.e. a new CPAN distribution, or new packages to the existing distro. Package IO::Iron::IronMQv3 side by side with IO::Iron::IronMQ. And copy the code.

choice: Let user choose which API version to use. Modify the existing functions so that calling the wrong functions, for example 'Get Messages'/IO::Iron::IronMQ::Queue::pull() without a message id is not possible in v3 (version 3), or calling 'Reserve Messages'/IO::Iron::IronMQ::Queue::reserve() is not possible when version is 1.

Both solutions pose difficulties. Branching is easier but creates more to maintain later when all bug fixes and improvements will need to be copied to the other branch. Choice creates a lot more work because every function must now have safeguards against calling them in the wrong way.

I am tempted to lean towards the second option. In my mind it would be more elegant and also more user friendly. User does not need to worry about rewriting all his code to use "IO::Iron::IronMQv3", only rewrite the code logic to accommodate to the workflow change.

Changes before V3 update

There will be at least one release of IO::Iron before the bigger IronMQ v3 compatible release. I have already fixed some "design failures" in versions up to 0.11.

I had used use warnings FATAL => 'all'; in all files. This was not only overkill but also clearly wrong as discussed in Perl Monks Meditations: "[..] Harmless warnings should not kill production code. They could (and perhaps should) be logged, so errors can be debugged later. [..]". I have changed it to simply use warnings; .

There was earlier available a configuration item host_path_prefix which essentially did the same thing as item api_version should have done. I have removed host_path_prefix completely from the code. This is an API breaking change and I apologize if this causes any harm - though I doubt it because the option had good default values. The meaning of the item api_version was not fully understood when designing IO::Iron.

I have added a method for new API function '/stacks' in IO::Iron::IronWorker::Client . It pulls a list of all available IronWorker stacks. Currently supported and available are the following stacks: go-1.4, scala-2.9, ruby-2.1, ruby-1.9, ruby-1.8, python-3.2, python-2.7, php-5.4, php-5.6, node-0.10, node-0.11, node-0.12, java-1.7, mono-3.0, crawler, selenium, newrelic, phantom-1.9, phantom-2.0, phantom-1.9-b, phantom-2.0-b, ffmpeg-2.3, php-5.5, java-1.8, mono-3.6, mono-2.10. Besides these some other stacks are available, but not officially or they are deprecated.

Fine-tuning done with the help of PerlCritic. Even the tests now pass PerlCritic.

This entry also published in Blog Exercises in Restful Integration and Continuous Delivery.