How to setup a FIFO queue to send commands

  • Platform information:
    • Hardware: Raspberry Pi 3 Model B Rev 1.2
    • OS: Raspbian GNU/Linux 8 (jessie)
    • Java Runtime Environment: don’t know
    • openHAB version: openHAB 2.3.0-1 (Release Build)
  • Issue of the topic: How to setup a FIFO queue to send commands

I am hoping to get some suggestions on how to solve this challenge.

Background: I have a ZMOTE device to control my TV and other entertainment devices. Through the use of HabPanel and rules those devices are being switched on, channel changed and so on.
The normal command to a device is as follows:

				zmote_ir1_sendcode.sendCommand("37000,1,1,332,164,22,19,21,20,21,61,21,20,22,19,22,19,21,20,22,19,22,60,22,60,22,19,22,60,21,61,21,61,21,61,22,61,22,60,22,19,22,19,22,60,22,19,22,19,22,19,22,19,22,19,21,61,22,60,22,19,21,61,21,61,22,60,22,61,22,1464,331,82,21,1101,331,82,21,1101,331,82,22,1100,331,82,21,1100,332,82,22,1100,331,82,21,1101,331,82,21,1101,331,82,21,1101,331,82,22,1099,332,82,22,1100,331,82,22,23,8,1068,332,82,22,1100,331,82,21,3692")

This is translated via the ZMOTE binding into an IR stream. The transmission of this commands takes some time as well as the processing/reaction at the receiving device (e.g. TV).
Since I have to send several commands in sequence (e.g. TV on, Receiver On, Change Channel to 7) I have a number of Thread::sleep() commands sprinkled throughout the rules (some lasting several hundred of ms).

Question: Instead of using discrete “zmote_ir1_sendcode.sendCommand” statements I would like to develop a sort of device driver that can handle the execution of these sendcode commands (which are strings) with associated wait times in between sendcode commands using a timer. I envision writing the sendcode commands and associated wait times into a FIFO, trigger the device driver and then let the device driver execute going through the FIFO, sending out the commands until the FIFO is empty.
An additional challenge would be the protection against quasi parallel calls of the device driver and handling the concurrency issues associated with that.
Any suggestions on how to do that are greatly appreciated

I read through the DP you referenced, but don’t understand the depth of OpenHab to see if multiple triggers to the proxy command are queued up and will execute in the order they were triggered?

After playing around with the referenced DP and realizing that the FIFO can not be a string item, I think I got it… By using a global string var to hold the FIFO items I came up with this test rule which seems to work nicely (I omitted the items definitions):

import java.util.concurrent.locks.ReentrantLock
var lock 		= new ReentrantLock
var FIFO 		= ""
var FIFOctr		= 0
val seperator 	= "|"

// ********************************************************
// System Startup Updates
// ********************************************************
rule "Startup Update"
when
	System started
then
        logInfo("FIFO", "ready")
        FIFO = ""
end

// **************************************************************
// Run through FIFO commands and execute them until FIFO is empty
// **************************************************************
rule "FIFO execution"
when
    Item TestSwitch2 received update
then
    // Ensures only one instance of the Rule can run at a time
   lock.lock
   try {
   		// The global variable FIFO contains the commands
   		// multiple commands are seperated by a special seperator string 
        // (which can not be part of the command of course)
		FIFOctr = FIFOctr + 1
		logInfo("FIFO", "                    FIFO #" + FIFOctr.toString + " execution enter...")

		while(!FIFO.isEmpty)
		{
			logInfo("FIFO", "                           while loop: " + FIFO)
			var cmdStr = ""
			// cover all edge cases; FIFO could look like this:
			// 	""					=> do nothing
			// 	"|"					=> do nothing
			// 	"||||"				=> do nothing
			// 	"cmd1"				=> execute cmd1
			// 	"cmd1|cmd2|cmd3"	=> execute cmd1 then cmd2 then cmd3
			// 	"|cmd1|cmd2|cmd3|"	=> execute cmd1 then cmd2 then cmd3
			// 	"|cmd1|cmd2|cmd3"   => execute cmd1 then cmd2 then cmd3
			// 	"cmd1|cmd2|cmd3|"   => execute cmd1 then cmd2 then cmd3
			var cmdSeperator = FIFO.indexOf(seperator)
			if (cmdSeperator>-1)
			{
				if (FIFO != seperator)
				{
					// extract command string
					cmdStr = FIFO.substring(0,cmdSeperator)
					// remove command string from FIFO
					FIFO   = FIFO.substring(cmdSeperator+1,FIFO.length())
				}
				else
				{
					// remove command string from FIFO (should now be empty, but just in case something else was added from another rules...)
					FIFO   = FIFO.substring(cmdSeperator+1,FIFO.length())
				}
			}
			else
			{
				// last command in FIFO
				cmdStr = FIFO
				FIFO   = ""
			}

			// check if valid command is available, then execute it
			if (!cmdStr.isEmpty && cmdStr != seperator)
			{
				logInfo("FIFO", "cmdStr: " + cmdStr)
				// do whatever needs to be done with the command..

				// sleep for a while just to simulate how long the command takes to execute, this is the reason for the FIFO
				Thread::sleep(500)
			}
		}
		logInfo("FIFO", "                    FIFO execution exit...")
   }
   catch(Exception e) {
       logError("FIFO", "Error handling FIFO command: " + e)
   }
   finally {
       lock.unlock
   }

end

rule "Test 1"
when
    Item TestSwitch1 received command
then
	FIFOctr = 0
	logInfo("test", "              test1 start trigger")

	// here are some test cases...

	// load up FIFO with an empty command and fire it off
	FIFO = FIFO + seperator + ""
	TestSwitch2.sendCommand(ON)

	// fire off another FIFO loading rule to see how they interact
	TestSwitch3.sendCommand(ON)
	FIFO = FIFO + seperator + "|"
	Thread::sleep(500)

	// load up FIFO with a single command and fire it off
	FIFO = FIFO + seperator + "ID0_"
	TestSwitch2.sendCommand(ON)

	// load up FIFO with multiple commands and fire it off
	// just for fun suspend for some time
	FIFO = FIFO + seperator + "ID1_"
	FIFO = FIFO + seperator + "ID2_"
	FIFO = FIFO + seperator + "ID3_"
	Thread::sleep(200)
	FIFO = FIFO + seperator + "ID4_"
	FIFO = FIFO + seperator + "ID5_"
	FIFO = FIFO + seperator + "ID6_"
	TestSwitch2.sendCommand(ON)

	Thread::sleep(400)
	FIFO = FIFO + seperator + "ID7_"
	FIFO = FIFO + seperator + "ID8_"
	FIFO = FIFO + seperator + "ID9_"
	Thread::sleep(100)
	FIFO = FIFO + seperator + "ID10_"
	FIFO = FIFO + seperator + "ID11_"
	FIFO = FIFO + seperator + "ID12_"
	TestSwitch2.sendCommand(ON)
	logInfo("test", "              test1 end trigger")
end

rule "Test 2"
when
    Item TestSwitch3 received command
then
	logInfo("test", "              test2 start trigger")
	// load up FIFO with commands
	FIFO = FIFO + seperator + ""
	TestSwitch2.sendCommand(ON)

	FIFO = FIFO + seperator + "ID13_"
	TestSwitch2.sendCommand(ON)
	logInfo("test", "              test2 end trigger")
end

The logInfo output for this looks like this:

2018-10-07 11:17:37.597 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - ready
2018-10-07 11:17:43.352 [INFO ] [org.eclipse.smarthome.model.script.test           ] -               test1 start trigger
2018-10-07 11:17:44.617 [INFO ] [org.eclipse.smarthome.model.script.test           ] -               test1 end trigger
2018-10-07 11:17:44.661 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                     FIFO #1 execution enter...
2018-10-07 11:17:44.672 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ||||ID0_|ID1_|ID2_|ID3_|ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_
2018-10-07 11:17:44.692 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: |||ID0_|ID1_|ID2_|ID3_|ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_
2018-10-07 11:17:44.705 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ||ID0_|ID1_|ID2_|ID3_|ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_
2018-10-07 11:17:44.718 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: |ID0_|ID1_|ID2_|ID3_|ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_
2018-10-07 11:17:44.729 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID0_|ID1_|ID2_|ID3_|ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_
2018-10-07 11:17:44.741 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID0_
2018-10-07 11:17:45.246 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID1_|ID2_|ID3_|ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_
2018-10-07 11:17:45.255 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID1_
2018-10-07 11:17:45.762 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID2_|ID3_|ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_
2018-10-07 11:17:45.780 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID2_
2018-10-07 11:17:46.289 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID3_|ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_
2018-10-07 11:17:46.309 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID3_
2018-10-07 11:17:46.817 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_
2018-10-07 11:17:46.837 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID4_
2018-10-07 11:17:47.346 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_
2018-10-07 11:17:47.365 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID5_
2018-10-07 11:17:47.874 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_
2018-10-07 11:17:47.890 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID6_
2018-10-07 11:17:48.399 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID7_|ID8_|ID9_|ID10_|ID11_|ID12_
2018-10-07 11:17:48.417 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID7_
2018-10-07 11:17:48.925 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID8_|ID9_|ID10_|ID11_|ID12_
2018-10-07 11:17:48.951 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID8_
2018-10-07 11:17:49.461 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID9_|ID10_|ID11_|ID12_
2018-10-07 11:17:49.472 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID9_
2018-10-07 11:17:49.979 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID10_|ID11_|ID12_
2018-10-07 11:17:49.997 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID10_
2018-10-07 11:17:50.505 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID11_|ID12_
2018-10-07 11:17:50.516 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID11_
2018-10-07 11:17:51.024 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID12_
2018-10-07 11:17:51.050 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID12_
2018-10-07 11:17:51.558 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                     FIFO execution exit...
2018-10-07 11:17:51.565 [INFO ] [org.eclipse.smarthome.model.script.test           ] -               test2 start trigger
2018-10-07 11:17:51.580 [INFO ] [org.eclipse.smarthome.model.script.test           ] -               test2 end trigger
2018-10-07 11:17:51.594 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                     FIFO #2 execution enter...
2018-10-07 11:17:51.601 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ||ID13_
2018-10-07 11:17:51.618 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: |ID13_
2018-10-07 11:17:51.634 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID13_
2018-10-07 11:17:51.647 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID13_
2018-10-07 11:17:52.153 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                     FIFO execution exit...
2018-10-07 11:17:52.167 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                     FIFO #3 execution enter...
2018-10-07 11:17:52.172 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                     FIFO execution exit...
2018-10-07 11:17:52.185 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                     FIFO #4 execution enter...
2018-10-07 11:17:52.192 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                     FIFO execution exit...
2018-10-07 11:17:52.384 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                     FIFO #5 execution enter...
2018-10-07 11:17:52.388 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                     FIFO execution exit...
2018-10-07 11:17:52.397 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                     FIFO #6 execution enter...
2018-10-07 11:17:52.404 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                     FIFO execution exit...

It is interesting to note, that the secondary rule that is triggered within the first rule does not execute until the first one is finished…

This is because of the lock

Well done

Please mark the thread as solved

I just want to add that even with your variable, there is nothing at all to guarantee the order of processing of events, particularly if they occur really really close together. OH isn’t a real time system and there are no checks in place to enforce the order. Usually this doesn’t matter because events don’t usually happen that close together, or if they do it doesn’t matter if they get processed out of order.

I’ll also caution you to make very certain that you do not have any errors in your code between the lock and the unlock. Some errors can occur that will not generate an exception that makes it back into the Rule and in those cases your finally will not execute and you lock will not become unlocked.

Thanks @rlkoshak for the input! I realize that OH is far from realtime. With multiple parallel processes running there is no guarantee at all, that some other process is also accessing the global FIFO variable and potentially destroying values that have been added by a first process. In general the FIFO is loaded through Habpanel associated interaction (controlling a TV and Entertainment Center). Those are generally not close together in time. But nevertheless, I wanted to have a more responsive UI, since some sequenced commands take longer (>1s). This can get annoying; e.g. hit the wrong button to select channel 1224 and then immediately hit the correct button to select channel 223; in this case if I don’t queue up the command sequence the second button hit will not be recognized and feels sluggish on the UI.
With respect to errors within the lock/unlock, I’ll find that out immediately, since my OH TV remote won’t respond anymore :wink:

It’s worse than that. No OH rules will at all until you restart OH.

Does that mean a lock is global, i.e. no other OH functions execute?

The title talks about Thread::sleep because they are the most common problem. But locks can pose the same problem.

Again thanks for the info. I need to study this a bit to see how I can utilize your “implement a while loop using Timers” suggestion, which has a lot of merits!

Ok, I thought about it and used the “Timer based while loop” to get rid of the Thread::sleep entries in the original while loop.
I do realize, that adding items to the FIFO asynchronous to the “FIFO execution” rule is dangerous and does result in crashes of the rule if timed right, which in combination with my new “FIFOrunning” check can result in a permanent stop of the rule execution (since FIFOrunning will not be set to false in the event of a rule Exception).
But in any case for the sake of experimenting, here it goes:

var FIFO 			= ""
var FIFOctr			= 0
val seperator 		= "|"
var Timer mytimer 	= null
var FIFOrunning 	= false

// ********************************************************
// System Startup Updates
// ********************************************************
rule "Startup Update"
when
	System started
then
		FIFOrunning=false
        FIFO = ""
        logInfo("FIFO", "ready")
end


// ********************************************************
// Run through FIFO commands and execute them FIFO is empty
// ********************************************************
rule "FIFO execution"
when
    Item TestSwitch2 received command
then
	// The global variable FIFO contains the commands
	// multiple commands are seperated by seperator

	// Prevent multiple executions
	if (FIFOrunning) return;

	logInfo("FIFO", "                    FIFO rule entry")
	FIFOrunning = true
	FIFOctr		= FIFOctr + 1
	logInfo("FIFO", "                    FIFO #" + FIFOctr.toString + " execution enter...")

	mytimer = createTimer(now, [ |
		if(FIFO.isEmpty)
		{
			mytimer = null
			FIFOrunning=false
			logInfo("FIFO", "                    FIFO execution exit...")
		}
		else
		{
			logInfo("FIFO", "                           while loop: " + FIFO)
			var cmdStr = ""
			// cover all edge cases; FIFO could look like this:
			// 	""					=> do nothing
			// 	"|"					=> do nothing
			// 	"||||"				=> do nothing
			// 	"cmd1"				=> execute cmd1
			// 	"cmd1|cmd2|cmd3"	=> execute cmd1 then cmd2 then cmd3
			// 	"|cmd1|cmd2|cmd3|"	=> execute cmd1 then cmd2 then cmd3
			// 	"|cmd1|cmd2|cmd3"   => execute cmd1 then cmd2 then cmd3
			// 	"cmd1|cmd2|cmd3|"   => execute cmd1 then cmd2 then cmd3
			var cmdSeperator = FIFO.indexOf(seperator)
			if (cmdSeperator>-1)
			{
				if (FIFO != seperator)
				{
					// extract command string
					cmdStr = FIFO.substring(0,cmdSeperator)
					// remove command string from FIFO
					FIFO   = FIFO.substring(cmdSeperator+1,FIFO.length())
				}
				else
				{
					// remove command string from FIFO (should now be empty, but just in case something else was added from another rules...)
					FIFO   = FIFO.substring(cmdSeperator+1,FIFO.length())
				}
			}
			else
			{
				// last command in FIFO
				cmdStr = FIFO
				FIFO   = ""
			}

			// check if valid command is available, then execute it
			if (!cmdStr.isEmpty && cmdStr != seperator)
			{
				logInfo("FIFO", "cmdStr: " + cmdStr)
				// do whatever needs to be done with the command..

				// delay for a while just to simulate how long the command takes to execute, this is the reason for the FIFO
				mytimer.reschedule(now.plusMillis(500))
			}
			else
				mytimer.reschedule(now)
		}
	])
	logInfo("FIFO", "                    FIFO rule exit")
end

rule "Test 1"
when
    Item TestSwitch1 received command
then
	FIFOctr = 0
	logInfo("test", "              test1 start trigger")

	// here are some test cases...

	// load up FIFO with an empty command and fire it off
	FIFO = FIFO + seperator + ""
	TestSwitch2.sendCommand(ON)

	// fire off another FIFO loading rule to see how they interact
	TestSwitch3.sendCommand(ON)
	FIFO = FIFO + seperator + "|"
	Thread::sleep(500)

	// load up FIFO with a single command and fire it off
	FIFO = FIFO + seperator + "ID0_"
	TestSwitch2.sendCommand(ON)

	// load up FIFO with multiple commands and fire it off
	// just for fun suspend for some time
	FIFO = FIFO + seperator + "ID1_"
	FIFO = FIFO + seperator + "ID2_"
	FIFO = FIFO + seperator + "ID3_"
	Thread::sleep(200)
	FIFO = FIFO + seperator + "ID4_"
	FIFO = FIFO + seperator + "ID5_"
	FIFO = FIFO + seperator + "ID6_"
	TestSwitch2.sendCommand(ON)

	Thread::sleep(400)
	FIFO = FIFO + seperator + "ID7_"
	FIFO = FIFO + seperator + "ID8_"
	FIFO = FIFO + seperator + "ID9_"
	Thread::sleep(100)
	FIFO = FIFO + seperator + "ID10_"
	FIFO = FIFO + seperator + "ID11_"
	FIFO = FIFO + seperator + "ID12_"
	TestSwitch2.sendCommand(ON)
	logInfo("test", "              test1 end trigger")
end

rule "Test 2"
when
    Item TestSwitch3 received command
then
	logInfo("test", "              test2 start trigger")
	// load up FIFO with commands
	FIFO = FIFO + seperator + ""
	FIFO = FIFO + seperator + "ID13_"
	TestSwitch2.sendCommand(ON)
	logInfo("test", "              test2 end trigger")
end

The logInfo output for this looks like this:

2018-10-08 23:26:28.673 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - ready
2018-10-08 23:27:12.352 [INFO ] [org.eclipse.smarthome.model.script.test           ] -               test1 start trigger
2018-10-08 23:27:13.626 [INFO ] [org.eclipse.smarthome.model.script.test           ] -               test1 end trigger
2018-10-08 23:27:13.646 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                     FIFO rule entry
2018-10-08 23:27:13.657 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                     FIFO #1 execution enter...
2018-10-08 23:27:13.673 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                     FIFO rule exit
2018-10-08 23:27:13.676 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ||||ID0_|ID1_|ID2_|ID3_|ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_
2018-10-08 23:27:13.686 [INFO ] [org.eclipse.smarthome.model.script.test           ] -               test2 start trigger
2018-10-08 23:27:13.702 [INFO ] [org.eclipse.smarthome.model.script.test           ] -               test2 end trigger
2018-10-08 23:27:13.703 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: |||ID0_|ID1_|ID2_|ID3_|ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_|ID13_
2018-10-08 23:27:13.744 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ||ID0_|ID1_|ID2_|ID3_|ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_|ID13_
2018-10-08 23:27:13.757 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: |ID0_|ID1_|ID2_|ID3_|ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_|ID13_
2018-10-08 23:27:13.771 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID0_|ID1_|ID2_|ID3_|ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_|ID13_
2018-10-08 23:27:13.780 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID0_
2018-10-08 23:27:14.285 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID1_|ID2_|ID3_|ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_|ID13_
2018-10-08 23:27:14.295 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID1_
2018-10-08 23:27:14.803 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID2_|ID3_|ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_|ID13_
2018-10-08 23:27:14.819 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID2_
2018-10-08 23:27:15.328 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID3_|ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_|ID13_
2018-10-08 23:27:15.346 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID3_
2018-10-08 23:27:15.857 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID4_|ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_|ID13_
2018-10-08 23:27:15.876 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID4_
2018-10-08 23:27:16.386 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID5_|ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_|ID13_
2018-10-08 23:27:16.401 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID5_
2018-10-08 23:27:16.909 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID6_|ID7_|ID8_|ID9_|ID10_|ID11_|ID12_|ID13_
2018-10-08 23:27:16.926 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID6_
2018-10-08 23:27:17.435 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID7_|ID8_|ID9_|ID10_|ID11_|ID12_|ID13_
2018-10-08 23:27:17.451 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID7_
2018-10-08 23:27:17.960 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID8_|ID9_|ID10_|ID11_|ID12_|ID13_
2018-10-08 23:27:17.980 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID8_
2018-10-08 23:27:18.489 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID9_|ID10_|ID11_|ID12_|ID13_
2018-10-08 23:27:18.507 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID9_
2018-10-08 23:27:19.025 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID10_|ID11_|ID12_|ID13_
2018-10-08 23:27:19.049 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID10_
2018-10-08 23:27:19.558 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID11_|ID12_|ID13_
2018-10-08 23:27:19.567 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID11_
2018-10-08 23:27:20.073 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID12_|ID13_
2018-10-08 23:27:20.091 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID12_
2018-10-08 23:27:20.597 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                            while loop: ID13_
2018-10-08 23:27:20.603 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] - cmdStr: ID13_
2018-10-08 23:27:21.111 [INFO ] [org.eclipse.smarthome.model.script.FIFO           ] -                     FIFO execution exit...

If my understanding is correct, the “FIFO execution” rule executes extremely fast (~30ms) and the timer is doing all of the heavy lifting.

To prevent the asynchronous corruption of the global FIFO would it be feasible to use a Lambda instead of the “FIFO execution” rule, with each rule providing its own FIFO buffer?

All things considered, you probably shouldn’t be implementing something like this yourself anyway. Use

or one of the other thread safe Queues that is appropriate for your use case.

Implementing a lambda is likely to only increase the likelihood that you will encounter errors that will leave your locks locked and your Rules deadlocked.

Now this opens another whole can of worms. I’ll have to research some examples on how to integrate these java classes in my rules files and how to interact with them…