I have an Qaction A that receives changes from a table and triggers Qaction B. Qaction A writes to an invisible string "buffer" param that Qaction B reads from and deletes. The problem is that the table may have multiple changes. So as Qaction A is triggered multiple times it also triggers Qaction B multiple times. So depending on when Qaction B is scheduled to run the buffer may not be completely filled with the changes. Is there any way to tell how many times Qaction A is scheduled to run, and then run Qaction B when its finished? Can I see how many changes are in the table? Or is this just a bad pattern all together?
Hi,
Is this table an SNMP table and is the QAction A triggering on this SNMP table?
Does the QAction A have the row="true" attribute specified? If that is the case then the QAction will go off multiple times when multiple rows are changing in the table. Remove the row="true" to have only one trigger when things are changing in the table.
To avoid having to work with a buffer parameter can be done by importing (precompiled) QAction B into QAction A. This way QAction A can directly use the methods of QAction B and pass the "buffer" value to the B method instead of having to go via a parameter that would have a more costly inter-process call.
If the code of QAction B is not shared with other logic that would be triggering this QAction then this code might as well be directly added to QAction A.
Regards,
Hi, I took a look at the Harmonic VOS that was mentioned in the reply to the answer of Michiel. Writes enter on QAction id 1000, this then modifies the buffer parameter 999 and starts group 998 that processes the buffer values on another thread in QAction id 998.
1) Is there a way to know how many sets/writes are still waiting to trigger QAction id 1000? No, there is no way to know this. QAction 1000 will be triggered set per set. This means if group 998 gets triggered fast enough that it could send multiple commands to the VOS instead of one with all items.
2) As QAction 1000 and 998 run in 2 different threads, it means that there could indeed be a race condition where both will be writing the buffer at the same time, which could result in items being handled twice or not at all. A locking mechanism will be needed between both QActions, or instead of working with a parameter, work with a shared thread safe queue or stack object between both QActions where items can be added/removed
I believe the best way of doing something will heavily depend on what you are trying to achieve and the context of what can be triggered. Would be good to understand a bit more about what you are trying to achieve. Could you add more information on your use case and why you want to use a buffer?
You can add logging to your QAction to figure out how many times it is triggering during development and how long it takes. It is highly recommended to keep logging as low as possible to keep the load on your disk low, so best to disable the debug logs again after you are done with development.
Buffers are typically something we use to avoid your connector being locked for long periods because of the QAction that takes long to execute. If you can split up what you want to do into parts that take less time, then you can work with a buffer. To make the connector responsive again between the items of the buffer, we need to add a group to the stack that will process the next item so that other groups can also be executed in between. Below is a screenshot that might help you understand where on the stack a group is added (depending on the type of action used to put it on the stack).
Maybe by playing with execute next and execute, you might be able to reduce the number of times you trigger certain actions. Using methods with the keyword one will avoid putting the same group on the stack if it is already on there. More info on actions can be found here: Actions overview | DataMiner Docs
Tips:
- Never save a buffer. Buffers change typically rather quickly and if saved it will on every change update the data in your DB, which will result in a lot of load on your DB layer. These issues can be difficult to solve later on (to find out why there is so much load on your DB).
- If you want to know what group your connector is currently executing you can use the protocol pending calls. To ensure your connector is responsive, you want to avoid it being stuck in the same group for longer periods.
- Try to reduce the protocol calls. If you are using protocol. (e.g. protocol.setparameter) methods, then try to reduce them (e.g. by using setparameters instead of the setparameter method) as much as possible as these will be the ones that typically generate the delays and/or generate the load on your system.
- If you are setting a parameter that triggers another QAction (without going through a group), then this will be immediate and no other actions can be done in between.
Sure, You can look at the code since its in an official SL Driver! I am describing in abstract the interaction between QA 1000 and QA 998 in the Harmonic VOS protocol. Basically the service table in the gui has a lot of writable params. If I make a bulk update to the table (make a lot of changes but save them all at once) QA 1000 starts writing the changes to a hidden string param but also triggers QA 998 to start reading and deleting the hidden string param. The intent I believe was to reduce the number of calls to the VOS server as all the changes to a service could be done in one call. However due to the race condition sometimes the changes are erased before being processed and/or more than one call is sent to the VOS server.
I had a quick look inside the connector and as far as I can see it is possible that a set is not executed when any of the values that you set contains a ‘|’ or a ‘backslash’ (this website removes my backslash). For service names, it can’t be null or whitespace or be a name that already exists. For the service rank, it can’t be the same to one that is already in the table. So if you are executing a lot of sets at once (even though when they would all execute you would have no duplicates), these conditions apply to what is currently in the table.
During the execution of the buffer, if an exception is thrown, the buffer will be cleared and other sets that should come after it might be lost. If this happens you should see a log entry that contains “SetService|Exception: “. If you want to see the service updates that are being made to the VOS server you can set debug logging to 1. Then you will find logging that contains “|SetService|Service object: ” for every service update made to the server. In the code I also found the following comment:
“This is a non DataMiner way that ended up to be the most safe way to implement this. The device has a unstable way of replying to a service PUT call. It’s not stable because via the “Dataminer way” the device drops the connection while at the same time it is configuring the changes internally in the device. While dropping just 2 seconds after slprotocol will trigger make a retry inducing the device to reply with a http 400 bad request where it states the described service ID is being configured. With the WebClient way the http connection does not get dropped and the http connection is hold for a longer time making it possible to wait for a proper reply.”
Can you have a look at the logging of the element to see if any exceptions happen for sets that would not happen? You could also increase the log level to figure out why certain sets are done twice. I assume at this point that it is because the buffer is executed before the next table set is processed.
No, this is a displayed table; Qaction B handles several triggers. To be clear I did not write this code. I would still need to know when the params are done triggering in Qaction A before I could call the methods in Qaction B. But because the write params directly call Qaction A I am unaware of a way to know how many changes were made