I was working on a project where I needed a pool of PowerShell workers that were distributed across several nodes and should be served by a central dispatcher. So why not give AMQP with RabbitMQ a try?
The setup was very easy thanks to the documentation. And besides plenty of .NET library wrappers around “Rabbit.MQ.Client.dll” there were even two PowerShell modules on the Developer tools list. However, as it turned out they had their limitations (like working via the HTTP interface instead of AMQP directly, or just providing too much functionality where I only needed a quick dispatcher/worker queue scenario).
So my first thought was to just “Add-Type” the “Rabbit.MQ.Client.dll” client and implement Send/Receive quickly by following the tutorials. But as it turned out this was not really working as the “Rabbit.MQ.Client.dll” assembly is not CLS compliant and therefore the “ConnectionFactory” could not be instantiated. A quick search revealed I was not the only one having this issue. So I decided to write a quick wrapper around it with a few convenience methods to be used in PowerShell. The idea was not to create a full replica of the original client or to create 667 PowerShell cmdlets but to expose as much from the original client as possible while being able to send and receive a message with as few command as possible. So here we are (code complies with VS2013):
In case your browser does not render the Gist correctly you can view the code directly at: https://gist.github.com/dfch/6da3d17414c913595302.
Usage is simple, you just add the assembly to your session (note: the assembly must be in the same path as the original RabbitMQ client dll) and then you specify server, username, password and your queue.
Receiving a message is nearly the same; call “Rceive()” and optionally specify the wait timeout:
There was a strange behavior I observed after connecting a consumer and receving from a queue. On the first fetch/dequeue operation with a WaitTimeout of 0 no message was returned. On a subsequent fetch the message was received. When using an infinite WaitTimeout (-1) the message was received on the first call.
In case you get an error while trying to connect to your AMQP server have a look at the ErrorRecord, especially the second InnerException of the Exception:
PS > $mq.Send("tralala"); Exception calling "Send" with "1" argument(s): "None of the specified endpoints were reachable" At line:1 char:1 + $mq.Send("tralala"); + ~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : BrokerUnreachableException PS > $error[0].Exception Exception calling "Send" with "1" argument(s): "None of the specified endpoints were reachable" PS > $error[0].Exception.InnerException None of the specified endpoints were reachable PS > $error[0].Exception.InnerException.InnerException ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN. For details see the broker logfile.
The broker log file (which you will find below the %APPDATA% folder) will sometimes give you more details, such as telling you about lacking permissions or wrong credentials:
=INFO REPORT==== 24-Aug-2014::01:12:59 === accepting AMQP connection <0.281.0> (amqpclient.example.com:54082 -> amqp.example.com:5672) =ERROR REPORT==== 24-Aug-2014::01:13:02 === closing AMQP connection <0.281.0> (amqpclient.example.com:54082 -> amqp.example.com:5672): {handshake_error,starting,0, {amqp_error,access_refused, "PLAIN login refused: user 'guest' can only connect via localhost", 'connection.start_ok'}} =INFO REPORT==== 24-Aug-2014::01:13:21 === accepting AMQP connection <0.286.0> (amqpclient.example.com:54083 -> amqp.example.com:5672) =ERROR REPORT==== 24-Aug-2014::01:13:24 === closing AMQP connection <0.286.0> (amqpclient.example.com:54083 -> amqp.example.com:5672): {handshake_error,starting,0, {amqp_error,access_refused, "PLAIN login refused: user 'Edgar.Schnittenfittich' - invalid credentials", 'connection.start_ok'}}
Note: if you have a fresh installation of RabbitMQ you might want to add a user so you can connect remotely to your server:
Create new user so we can connect from remote C:\> rabbitmqctl.bat add_user Administrator P@ssL0rd Make this user read/write admin C:\> rabbitmqctl.bat set_user_tags Administrator administrator C:\> rabbitmqctl.bat set_permissions -p / Administrator .* .* .* C:\> rabbitmqctl.bat list_users Listing users ... Administrator [administrator] guest [administrator] ...done. C:\> rabbitmqctl.bat list_permissions Listing permissions in vhost "/" ... Administrator .* .* .* guest .* .* .* ...done.
And it is always a good idea to watch your connections, consumers, queues and the like:
C:\> rabbitmqctl.bat list_connections Listing connections ... Administrator 192.168.174.148 53825 running Administrator 192.168.174.148 53828 running ...done. C:\> rabbitmqctl.bat list_queues Listing queues ... default 0 q2 0 q3 1786889 task_queue 0 ...done. C:\> rabbitmqctl.bat list_consumers Listing consumers ... q3 <rabbit@amqpserver.1.1609.0> amq.ctag-K1U5l7foM-7RDhxfcgOwTw true 1 [] q3 <rabbit@amqpserver.1.1665.0> amq.ctag-fB8dS9ZeJt9jNDP4EbCuBw true 1 [] ...done.
Reblogged this on Dinesh Ram Kali..