Java concurrent queue for tag change scripts

Continuing the discussion from [SOLVED] Are tag Value Changed scripts running asynchronously?:

We've got code in our standard library that I need to log a value change on a tag and then associate various data points with that value change. The value is located in a UDT, and because this is part of our "standard" library we use for our customers, the number of tags is variable and quite possibly numerous so having a gateway tag event script isn't feasible for this solution.

I was reading up on the above-linked thread, and @pturmel mentioned using a Java concurrent queue. Does anyone have any pointers where I can start developing a solution for this?

In reading it seems that I would want to use a ConcurrentLinkedQueue, and add a dictionary of the parameters that are then serviced later on a timer event.

Or am I way off base here?

Sounds about right. Not off base.

1 Like

So a slight issue when testing.

This is basically my code:

from java.lang import Throwable,System
from java.util.concurrent import ConcurrentLinkedQueue

thisQueue = ConcurrentLinkedQueue()

def logEmbeddedInterlock(tag,tagPath,previousValue,currentValue,initialChange)
	logger = 'testing'
	dictData = 	{
		'tag':tag,
		'tagPath':tagPath,
		'previousValue':previousValue,
		'currentValue':currentValue,
		'initialChange':initialChange
	}
	success = thisQueue.offer(dictData)
	logger.tracef('%s' % 'Offered {} to thisQueue. Success: {}'.format(dictData,success))
	logger.tracef('%s' % 'thisQueue length after offer: {}'.format(len(thisQueue.toArray())))

def serviceQueue():
	logger = 'testing.serviceQueue'
	logger.tracef('%s' % 'thisQueue length at start of serviceQueue: {}'.format(len(thisQueue.toArray())))
	while thisQueue.peek():
		interlockData = thisQueue.peek()

		tag = interlockData['tag']
		tagPath = interlockData['tagPath']
		previousValue = interlockData['previousValue']
		currentValue = interlockData['currentValue']
		initialChange = interlockData['initialChange']
		if not initialChange:
				logger.tracef('%s' % 'Got interlock data: {}'.format(interlockData))
				#Do things with the data
		else:
			thisQueue.remove(interlockData)	

I'm calling the logEmbeddedInterlock from the Tag Value Changed event.
I know it is firing, because I'm seeing an increase of the number of items in the thisQueue object in the logger.

However, when the timer script is firing off to call serviceQueue(), the number of items is being reported as 0.

The project is setup like so: scripting project -> GUI object project -> HMI Project.

The gateway has a reference to the scripting project for the tags, and the timer script is running in the HMI Project (the only runnable project on the system)

Do I need to be packing the queue object into system.util.getGlobals() when a new object is offered/removed? Or is there something else I'm missing somewhere along the way?

You absolutely must use my globalVarMap() or system.util.getGlobals() to coordinate access to a single ConcurrentLinkedQueue, with careful application of .setdefault to not smash a prior instance.

Also, keep in mind that ConcurrentLinkedQueue is unbounded--if you screw up the draining, you will leak gobs of memory. Consider using LinkedBlockingQueue with a capped size.

2 Likes