sendHttpGetRequest - TimeoutException

rules
httpbinding
sendhttpgetrequest
Tags: #<Tag:0x00007fae06cd5788> #<Tag:0x00007fae06cd55f8> #<Tag:0x00007fae06cd5378>

(Dries) #1

Hi,

I’m using the “sendHttpGetRequest” to send text messages (SMS) to my phone in case certain events occur.
Yesterday I “missed” an important event. The cause was found in openhab.log:

2017-06-09 15:53:48.136 [INFO ] [g.eclipse.smarthome.model.script.SMS] - SMS API Call initiated
2017-06-09 15:53:53.139 [ERROR] [.smarthome.model.script.actions.HTTP] - Fatal transport error: java.util.concurrent.TimeoutException
2017-06-09 15:53:53.140 [ERROR] [.script.engine.ScriptExecutionThread] - Rule 'Send SMS when Alarm is triggered': cannot invoke method public boolean java.lang.String.startsWith(java.lang.String) on null

The time-out exception is triggered when no response has been received for 5000ms.
I have now increased this to 10000ms seconds (in http.cfg).

But I was wondering, is there a way to “catch” that exception in my rule? This allows me to execute a plan B (try to send the text again, or send a Pushover message).

Thanks,
Dries


(Rich Koshak) #2
try{
    // Code goes here
}
catch(java.util.concurrent.TimeoutException e){
    logWarn("error", "received timeout exception blah blah blah")
}

(Dries) #3

Thanks!
I tried to implement your suggestion.
Since I couldn’t replicate the time-out issue, I changed the domainname I wanted to call. This leads to a “java.nio.channels.UnresolvedAddressException”. I wanted to see if I could catch that.

Here is an extract from my code:

		var urlmessage = "https://klanten.bizzsms.pnl/api/send?username=" + sms_username + "&code=" + sms_code + "&text=" + sms_text_encoded + "&phonenumbers=" + sms_recipient + "&sendertitle=" + sms_sendertitle
		
		logInfo("SMS","SMS API Call: " + urlmessage)

		try{
    		var sms_returnvalue = sendHttpGetRequest(urlmessage)
		}
		catch(java.nio.channels.UnresolvedAddressException e){
			logWarn("error", "received timeout exception")
			 sms_returnvalue = "Sending SMS failed"
		}
			
		if (sms_returnvalue.startsWith("1|0|")) {
			logInfo ("SMS", "SMS has been delivered")
			true
		} 
		else {
			logInfo ("SMS", "SMS was not delivered! " + sms_returnvalue)
			false
		}

When running this code, I still get:

2017-06-11 17:20:45.986 [INFO ] [g.eclipse.smarthome.model.script.SMS] - SMS API Call: https://klanten.bizzsms.pnl/api/send?username=blablabla
2017-06-11 17:20:46.016 [ERROR] [.smarthome.model.script.actions.HTTP] - Fatal transport error: java.util.concurrent.ExecutionException: java.nio.channels.UnresolvedAddressException
2017-06-11 17:20:46.017 [ERROR] [.script.engine.ScriptExecutionThread] - Rule 'Test SMS functionality': The name 'sms_returnvalue' cannot be resolved to an item or type.

So somehow, I didn’t catch it correctly?


(Rossko57) #4

I think that means the var only exists within the { } ?
Try using var outside of the block, so you are assigning or testing values only inside the blocks.


(Rich Koshak) #5

In addition to what @rossko57 identified, for whatever reason the code is throwing a different exception this time rather than the UnresolvedException.

You can catch Throwable which will catch any and all exceptions that could occur (Throwable is the root class of all Exceptions).

Usually I will put the code fur my entire rule inside the try because of an exception is thrown I don’t want the rest of the code to execute. A quick view of of your code does you don’t want the coffee that is after the catch to run either if the exception is thrown.


(Dries) #6

Hi both,

Thank you very much. I was able to catch my first exception. :slight_smile:

However, eventually I decided for a different approach.
I noticed that when the HTTP GET fails, the exception is not really on the first line of the rule-extract mentioned below. Technically it is processed fine, but the value of “sms_returnvalue” is just ‘null’. So I updated the rule so it does stuff when sms_returnvalue == null.

var sms_returnvalue = sendHttpGetRequest(urlmessage)
if (sms_returnvalue == null) {
			// Do stuff here in case the HTTP GET throws an error/is unreachable/...
}

(AlexKay) #7

Hi @rlkoshak,
Unfortunately I am not able to catch a TimeoutException when using sendHttpGetRequest in openHAB 2.1 (stable) along with your code example :frowning:

Do I miss an import statement or anything else?
Instead of “// Code goes here” from your example, I replaced it with "sendHttpGetRequest(http://LongRunningURL, 100)"
LongRunningURL takes 20s to complete, so 100ms is definitely to short to let it complete.

It still throws an TimeoutException in openhab.log and I am not able to catch it successfully :frowning:


(Rich Koshak) #8

Change the catch to catch all exceptions

catch(Exception e){

(AlexKay) #9

Hello Community,
it drives me crazy… I am still not able to catch a TimeoutException, Exception or any Throwable :frowning:
As you can see, it is a simple rule which does not need a thing, an item or anything else.
openHAB 2.1 stable is installed on Debian Linux 9.0 (was the same with 8.x) using openjdk-8-jre-headless

rule "Test1"
	when
		Time cron "1 * * * * ?"
	then
		logInfo("RULE","@R Test1: start try-catch-block")
		try{
			// TimeoutException expected, because URL needs 20000 ms to complete
			sendHttpGetRequest(http://LongRunningURL, 100)
		}
		//catch(java.util.concurrent.TimeoutException e){
		//catch(Exception e){
		catch(Throwable t){
			logInfo("RULE","@R Test1: catched exception/throwable")
		}
		logInfo("RULE","@R Test1: end try-catch-block")
end

/var/log/openhab2/openhab.log :

2017-08-25 10:35:01.000 [INFO ] [.eclipse.smarthome.model.script.RULE] - @R Test1: start try-catch-block
2017-08-25 10:35:01.101 [ERROR] [.smarthome.model.script.actions.HTTP] - Fatal transport error: java.util.concurrent.TimeoutException
2017-08-25 10:35:01.102 [INFO ] [.eclipse.smarthome.model.script.RULE] - @R Test1: end try-catch-block

Do I miss an import statetment? Anything else?
Your ideas are welcome!
Thanks in advance!


(Rich Koshak) #10

Based on the behavior I’m guessing the http action code catches the timeout itself, logs it and doesn’t rethrow it so the exception never gets to your rule code.

You will have to detect the timeout some other way.

Does the action return anything when it times out? Even if it returns nothing but you are expecting something that can be enough to detect the timeout.

If not, you may have to implement the call using the native Java classes. Look for the iCloud Integration tutorial for an example.


(AlexKay) #11

Hi @rlkoshak,
thanks again for spending your time and your hints.
Your explanation that the exception is catched in sendHttpGetRequest and not rethrown sounds reasonable, especially when I look again at the log entry which looks formatted by another class.

My primary goal is to trigger this HTTP request and continue processing in openhab without waiting until HTTP has finished (it triggers recording from 2 cameras handled by another system).
I need openHAB avoid waiting 20 seconds.

Is it possible to send sendHttpGetRequest(MyURL, 20000) to a background thread? In background it may take its time to complete.
Otherwise I consider calling a shell script which returns immediately while e.g. curl MyURL finishes in background , so that openhab can continue.
…or simply live with the “fatal transport error” in openhab.log

Good hint implementing it in Java, but my Java experience has been 15 years ago without deeper practice since…it would take me ages :slight_smile:


(Rich Koshak) #12

All of openHAB doesn’t wait for 20 seconds. Just that one rule. All your other rules and everything else will continue to run.

However, if you need to process the rest of that rule without waiting then you can apply the Separation of Behaviors Design Pattern. the tl;dr is to send a command to an unbound Item which triggers a rule to make the http request.

That being said, given your stated goal, what did you hope to accomplish by catching the TimeoutException? Even if the Action threw the exception back into the rule you would still have had to wait the 20 seconds in order to catch it.

That is why I sent you to a posting with an actual working example. Which, now that I’m not on my phone I can more easily provide the actual link:


(AlexKay) #13

Hi @rlkoshak,
I was not precise enough. I meant the rule waiting, not all of openHAB.
My try was to

sendHttpGetRequest(http://LongRunningURL, 100)

with a Timeout of 100 ms, in order to catch the TimeoutException very early and ignoring it instead of an error message in log like “Fatal transport error: java.util.concurrent.TimeoutException”.

But now I found a less complex way to accomplish the rule not waiting 20,000 ms. I simply create a Timer which fires immediately and executes sendHttpGetRequest in a parallel thread:

createTimer(now) [|
     sendHttpGetRequest(http://LongRunningURL, 20000)
     logInfo("RULE","LongRunningURL finished")
]

“Separation of Behaviors Design Pattern” is great! I will use it to evolve my rule file and centralize repeating logic in one place which can be maintained better!

I appreciate your help very much! Thanks!


(Rich Koshak) #14

But rules are already executed in separate threads. You could put a timeout of 20000000000 and only that one rule will be waiting for a response. It won’t cause all of OH to stop and wait and it won’t stop other rules or even other instances of that rule from executing.