This is great, Phil, much appreciated!! I'm plugging it in now.
This would be awesome!
Related to the premise of this thread, and maybe it's an insurmountable task, but it'd also be great to have a reference of things not to do in Ignition. With so many ways that you can technically do things, if you don't have a solid background in Java/Python programming (i.e. a software developer), there are so many ways you can shoot yourself in the foot (and step on a bear trap with the other). Often these don't become apparent until you start seeing performance issues on a system that's grown much larger over time. And more often than not, you don't even know where to start, or what part of your code is the culprit. At least if we have a growing list of things to avoid, then we might have better chance of avoiding at least some of the mistakes. I imagine that your support team, as well as everyone here on the forums, would have a list, at least in your heads (although support hopefully have this documented somewhere in a KB), of the common things that integrators do that they shouldn't. Pinging @Paul.Scott for your thoughts for an addition to the user manual perhaps?
I did, and it is !
But you can't beat built-in in terms of simplicity.
And by that, I mean a built-in solution would be documented in IA's doc, referenced in the functions index, it would also be a standard that other people use, which means threads with tips, use cases and examples on the forum, and you would not need to add it to your script library.
It would just be there for you to call.
Now, I agree that having a custom implementation of something can sometimes be easier, as you can just go and look at the code to figure out how it works, or change it a little bit to suit your needs... but that's out of the scope of my initial comment.
It's now, after getting an error running the decorator part, that I realise I never knew avout decorator functions... Into the rabbit hole I go!
As an aside, I'm sure there are a million other things I'm simply unaware of... I think I need to do some formal learning on Python
For context, when calling this part from your docstring, @pturmel :
processABCqueue = queueUtil.WrappedBlockingQueue('processABC', 100)
@queueUtil.drainEvents(processABCqueue, 100, 'Process ABC')
def processABC(entry):
# Unpack the entry to its components.
tagPath = entry
# Do whatever is needed.
I get the error:
TypeError: drainEvents() takes exactly 4 arguments (3 given)
def drainEvents(queue, maxPer, logPrefix):
"""Decorator that provides queue iteration and simple error handling.
Args:
f (callable): The bare function object to decorate.
queue (WrappedBlockingQueue): The queue to iterate through.
maxPer (int): Limit to iteration. Typically similar to queue capacity.
logPrefix (str): Message to include with logged throwables and exceptions.
`f` must take one argument: the entry taken from the head of the queue.
The resulting function should be called from a gateway timer event at a pace
that keeps the queue from filling up and meets the typical latency requirements
of the application.
Returns:
callable: Decorated function. Note that the resulting callable TAKES NO ARGS.
"""
def innerDrain(f):
processed = 0
entry = queue.poll()
while entry:
try:
f(entry)
except Throwable, t:
logger.warn(logPrefix, t)
except Exception, e:
logger.warn(logPrefix, later.PythonAsJavaException(e))
processed += 1
if processed > maxPer:
break
entry = queue.poll()
return innerDrain
I'm still getting my head around decorators... I understand the basics, but the cogs are still turning understanding them in a more complex context!
Edit: oh wait, looks like you might have edited it already to that?
@pturmel I think this part of the doco is missing the actual processABC() call:
Typical usage in a library script in a leaf project, called from a timer event:
processABCqueue = queueUtil.WrappedBlockingQueue('processABC', 100)
@queueUtil.drainEvents(processABCqueue, 100, 'Process ABC')
def processABC(entry):
# Unpack the entry to its components.
tagPath, currentValue, initialChange, missedEvents = entry
# Do whatever is needed.