# AMQP(RabbitMQ) in Ignition

**URL:** <https://forum.inductiveautomation.com/t/amqp-rabbitmq-in-ignition/60400>\
**Category:** Ignition\
**Tags:** perspective, ignition81, scripting\
**Created:** [June 6, 2022, 1:15pm UTC](https://forum.inductiveautomation.com/t/amqp-rabbitmq-in-ignition/60400 "2022-06-06T13:15:34Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![louagejasper](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/louagejasper/32/86311_2.png) [@louagejasper](https://forum.inductiveautomation.com/u/louagejasper)\
**Post date:** [June 6, 2022, 1:15pm UTC](https://forum.inductiveautomation.com/t/amqp-rabbitmq-in-ignition/60400/1 "2022-06-06T13:15:34Z")

</div>

Hi,

I’ve been trying to use AMQP in Ignition, using the amqp-client-5.14.2.jar library.  
For now, I’ve just added the library to the folder in Ignition, maybe later, I will build a separate module for it.

I have used the following code:

```auto
from com.rabbitmq.client import Connection
from com.rabbitmq.client import Channel
from com.rabbitmq.client import Consumer
from com.rabbitmq.client import DefaultConsumer
from com.rabbitmq.client import ConnectionFactory

userName = 'guest'
password = 'guest' 
virtualHost = "/"
hostName = "rabbitmq"
portNumber = 5672 #15672

exchangeName = 'EXCH'
queueName = 'Ignition'
routingKey = 'Ignition'

def connect():
	factory = ConnectionFactory()
	#"guest"/"guest" by default, limited to localhost connections
	factory.setUsername(userName)
	factory.setPassword(password)
	factory.setVirtualHost(virtualHost)
	factory.setHost(hostName)
	factory.setPort(portNumber)
	
	conn = factory.newConnection()
	channel = conn.createChannel()
	
	channel.queueBind(queueName, exchangeName, routingKey)
	autoAck = False
	channel.basicConsume(queueName, autoAck, "Ignition_Consumer", DefaultConsumer(channel))
	

```

This gives me a connection to the broker:

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/7/9/797cc69ce1a55917d9f44ba531d4e4476b5d579e.png)

Now I lack a bit of knowledge to proceed. Everytime I run the script, I logically get a new connection.

In the same script, I have this function:

```auto
def close():
	system.perspective.print('closing connection ...')
	channel.close()
	conn.close()

```

But this function is not connected anymore to the connection I first created, so it gives an error.

How do I make sure there is always one connection from my platform to the AMQP broker?  
And how do I manage that active connection without ?  
I assume I need something like persistent classes? @pturmel, I’ve seen you talk allot about classes an persistent classes, would you know how I can proceed?

Thanks!

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [June 6, 2022, 2:34pm UTC](https://forum.inductiveautomation.com/t/amqp-rabbitmq-in-ignition/60400/2 "2022-06-06T14:34:16Z")

</div>

I’d definitely recommend doing some digging on the forums for “prior art” here. One other thing to note: `system.util.globals` / `system.util.getGlobals()` is a dictionary that persists across the lifetime of the local JVM (so as long as the gateway is up).

---

<div class="post-metadata">

**Author:** ![louagejasper](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/louagejasper/32/86311_2.png) [@louagejasper](https://forum.inductiveautomation.com/u/louagejasper)\
**Post date:** [June 7, 2022, 8:23am UTC](https://forum.inductiveautomation.com/t/amqp-rabbitmq-in-ignition/60400/3 "2022-06-07T08:23:05Z")

</div>

I did do some digging here

> [@\[IGN-5244\]Persist Python Class Object](https://forum.inductiveautomation.com/t/ign-5244-persist-python-class-object/30498):
>
> I am working in Perspective, but this probably applies to other modules as well. I have created user defined classes in the project scripts and I am instantiating them from a view in Perspective. Is there a place I can persist the instance of the object for use between events by the user? Right now I have it serializing to a property on the view, but when I want to work with the object again I have to de-serialize the object in order to work with it again. Having to write custom de-serialize me…

and here

> [@system.util.getGlobals() not persisted across Designer Save](https://forum.inductiveautomation.com/t/system-util-getglobals-not-persisted-across-designer-save/33869/14):
>
> Ok. New module “Life Cycle” w/ system.util.persistent(name) utility function. For v7.9: [https://www.automation-pros.com/ignition/Life%20Cycle-0.9.0.2004121825.modl](https://www.automation-pros.com/ignition/Life%20Cycle-0.9.0.2004121825.modl) For v8.0: [https://www.automation-pros.com/ignition/Life%20Cycle-0.9.0.2004121920-v8.modl](https://www.automation-pros.com/ignition/Life%20Cycle-0.9.0.2004121920-v8.modl) Test with a project script like this: # project script "Life" g = system.util.persistent('LifeTest') count = g.setdefault('editCount', -1) count += 1 g['editCount'] = count def editCount(): return count Print the return from Life.editCou…

But I think you guys are a few levels ahead of me.  
I simply want one always open connection (I need a class for this I think) when Ignition is running and want to speak to this connection when necessary.  
How can I use `system.util.getGlobals()` to store a class? Is there any example on this?

And also, I'm a bit confused about `system.util.getGlobals()`. Are these globals something on your gateway? Because I see they are different when I open a new designer session.

\*Edit: Ah, it is the same when you run it in a gateway scope, I see... Now I just need to find how I can store my connections in it.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [June 7, 2022, 11:52am UTC](https://forum.inductiveautomation.com/t/amqp-rabbitmq-in-ignition/60400/4 "2022-06-07T11:52:40Z")

</div>

The point of those topics is that you _ **CAN’T** _ just “store a class”. You will leak gobs of gateway memory if you try to do it naively. On this topic, you will simply have to study and test until you understand it. I strongly recommend testing on a non-production gateway.

---

<div class="post-metadata">

**Author:** ![louagejasper](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/louagejasper/32/86311_2.png) [@louagejasper](https://forum.inductiveautomation.com/u/louagejasper)\
**Post date:** [June 7, 2022, 12:04pm UTC](https://forum.inductiveautomation.com/t/amqp-rabbitmq-in-ignition/60400/5 "2022-06-07T12:04:22Z")

</div>

Oh, ok… So referring back to my original code:

```auto
conn = factory.newConnection()

```

How would I typically refer back to a connection made in a script? Would the connection have some identifier, which I would need to store in globals and use later?

Ofcourse, I’m testing all new things in local containers.

---

<div class="post-metadata">

**Author:** ![Chris\_Bingham](https://avatars.discourse-cdn.com/v4/letter/c/e5b9ba/32.png) [@Chris\_Bingham](https://forum.inductiveautomation.com/u/Chris_Bingham)\
**Post date:** [July 13, 2022, 3:45pm UTC](https://forum.inductiveautomation.com/t/amqp-rabbitmq-in-ignition/60400/6 "2022-07-13T15:45:11Z")

</div>

We are heading down the same path. Currently working on a module which wraps the latest AMQP Client library.  
You can reference the same global variables within each of your functions:

```auto
def close():
	global conn // Added
	global channel // Added
	system.perspective.print('closing connection ...')
	channel.close()
	conn.close()

```

Have you made progress on a ‘unique connection identifier’?  
Found this related StackOverflow thread:

> <https://stackoverflow.com/questions/24910502/is-it-necessary-to-rebuild-rabbitmq-connection-each-time-a-message-is-to-be-sent>

---

<div class="post-metadata">

**Author:** ![louagejasper](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/louagejasper/32/86311_2.png) [@louagejasper](https://forum.inductiveautomation.com/u/louagejasper)\
**Post date:** [July 14, 2022, 2:04pm UTC](https://forum.inductiveautomation.com/t/amqp-rabbitmq-in-ignition/60400/7 "2022-07-14T14:04:27Z")

</div>

Hi Chris,

Yes I did. I store my connection in getGlobals, and this seems to work across sessions.

```auto
def connect():
	factory = ConnectionFactory()
	factory.setUsername(userName)
	factory.setPassword(password)
	factory.setVirtualHost(virtualHost)
	factory.setHost(hostName)
	factory.setPort(portNumber)
	g = system.util.getGlobals()
	if not "AMQP" in g:
		g["AMQP"] = {}
	gAMQP = g["AMQP"]
	if not "conn" in gAMQP:
		conn = factory.newConnection()
		gAMQP["conn"] = conn
	else:
		conn = gAMQP["conn"]
	if not "channel" in gAMQP:
		channel = conn.createChannel()
		gAMQP["channel"] = channel
		channel.queueBind(queueName, exchangeName, routingKey)
		#with basicConsume, we become a consumer, so we will be taking all messages from the queue and process it
		#Keep in mind this is pub/sub, but will automatically read all messages in queue on connect
		tag = channel.basicConsume(queueName, autoAck, newMessage, cancel, shutdown)
		gAMQP["consumerTag"] = tag
	else:
		channel = gAMQP["channel"]

```

Yes, we will be working on an AMQP module as well, somewhere in the future.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [July 14, 2022, 2:34pm UTC](https://forum.inductiveautomation.com/t/amqp-rabbitmq-in-ignition/60400/8 "2022-07-14T14:34:17Z")

</div>

> [@louagejasper](#):
>
> I store my connection in getGlobals

Racy. Try this:

```python
import thread

# Returns channel. If was a new channel, consumerTag is created too.
def conditionalConnect():
	g = system.util.getGlobals()
	# Ensure gAMQP exists in a thread-safe manner
	gAMQP = g.setdefault("AMQP", {})
	# Attempt to get the channel unlocked for speed
	channel = gAMQP.get("channel")
	if channel:
		return channel
	# Obtain and use lock
	channelLock = _g.get('channelLock', None)
	if channelLock is None:
		channelLock = _g.setdefault('channelLock', thread.allocate_lock())
	with channelLock:
		# Retry under the lock in case another thread was already in the
		# creation sequence.
		channel = gAMQP.get("channel")
		if channel:
			return channel
		# Nope. Connect and create and consume.
		factory = ConnectionFactory()
		factory.setUsername(userName)
		factory.setPassword(password)
		factory.setVirtualHost(virtualHost)
		factory.setHost(hostName)
		factory.setPort(portNumber)
		conn = factory.newConnection()
		channel = newConn.createChannel()
		channel.queueBind(queueName, exchangeName, routingKey)
		#with basicConsume, we become a consumer, so we will be taking all messages from the queue and process it
		#Keep in mind this is pub/sub, but will automatically read all messages in queue on connect
		tag = channel.basicConsume(queueName, autoAck, newMessage, cancel, shutdown)
		gAMQP['conn'] = conn
		gAMQP['channel'] = channel
		gAMQP["consumerTag"] = tag
		return channel

```

---

<div class="post-metadata">

**Author:** ![louagejasper](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/louagejasper/32/86311_2.png) [@louagejasper](https://forum.inductiveautomation.com/u/louagejasper)\
**Post date:** [July 14, 2022, 3:12pm UTC](https://forum.inductiveautomation.com/t/amqp-rabbitmq-in-ignition/60400/9 "2022-07-14T15:12:24Z")

</div>

Thanks for the upgrade!
