In a nut shell, Im making an api call that returns a number say “0”. Eventually (typically within 10 to 60 seconds) this api call will return me another number, say “1”, and when it does, I want to inform it was successful.
Right now I have the following code.
panelMetaData(token,locationID){
// some HTTP call
log.debug alarmCode
return alarmCode
}
arm() {
//some HTTP call
def metaData = panelMetaData(token, locationId) // Get AlarmCode
while( metaData.alarmCode != 10201 ){
pause(2000) // Two Second Pause to relieve number of retried on while loop
metaData = panelMetaData(token, locationId)
}
sendPush("Home is now Armed successfully")
}
However, intermetently I see my code throwing error
error java.util.concurrent.TimeoutException: Execution timed out after 40 units. Start time: <some date> @ line <some line>
which I get it as, Im making my code do “stupid” recursive calls to get a confirmation. Now I have read several post talking about use case of runIn() and runOnce() in this situation, but to my non developer nature Im not able to get understanding of how I can implement this in my code. Anyone can throw some light or some suggestions?
@obycode - Im yet to implement your work around, so I will update you later
@Chris - By increasing the pause/delay time, I think, I do reduce the number of API call it makes. Not sure if this will help me in the "Timeout Exception"situation as it seems sometimes, it requires more than 40 seconds for the api call to return correct code. Also doing so I reduce the frequency of alerting the user in amount in order of 10 seconds. I understand its a trade-off, but if it will work, Im all for it. Here are two examples of log messages (with the same code) showing how intermittent it is.
Didnt work:
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:33 AM: error java.util.concurrent.TimeoutException: Execution timed out after 40 units. Start time: Thu Nov 12 17:40:53 UTC 2015 @ line 75
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:31 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:29 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:27 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:25 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:22 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:24 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:20 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:16 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:18 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:13 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:14 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:11 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:09 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:07 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:03 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:02 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:05 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:41:00 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:40:58 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:40:56 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:40:54 AM: debug AlarmCode is 10307
Worked:
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:45:46 AM: debug Smart Things has successfully logged out
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:45:46 AM: debug During logout - 507BC822-5FF6-4173-876F-63DAD4204D8D
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:45:46 AM: debug Home is now Disarmed
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:45:46 AM: debug AlarmCode is 10200
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:45:44 AM: debug This was given as Location - Home
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:45:44 AM: debug Smart Things has logged In. SessionID: 507BC822-5FF6-4173-876F-63DAD4204D8D
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:45:43 AM: debug Executed login
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:45:43 AM: debug Reset the switch
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:45:27 AM: debug Smart Things has successfully logged out
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:45:27 AM: debug During logout - A4AB15A3-1998-4FE3-BA67-BE891DFCEC59
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:45:27 AM: debug Home is now Armed successfully
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:45:27 AM: debug AlarmCode is 10201
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:45:26 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:45:26 AM: debug AlarmCode is 10307
6c23a7ae-86f6-4447-bfd8-549cf612b643 11:45:24 AM: debug This was given as Location - Home
@obycode I have been contemplating about this for a while
Can you (or anyone else) help me understand the difference between runIn() vs pause() in both the example? I would like to understand why is one better over the other in SmartThings from the execution point of view.
Also tagging @Dianoga & @pstuart to this discussion as they had in past recommended suggestions around this.
I’m not entirely sure how pause or runIn work, but I’ll guess.
Pause could be some kind of busy wait, in which case that would explain why the SmartApp hits the timeout. It could be like a coroutine yield, which would save state and release resources while paused.
The runIn is definitely releasing resources and setting a timer to call the specified function. It doesn’t require saving any additional state.
runIn() schedules a new execution of this SmartApp, calling the method specified in the number of seconds specified. With values less than 60 seconds, YMMV.
pause() simply suspends the current thread, for the number of milliseconds specified (not to exceed 15 seconds).
pause() is unsupported and should not be used. It will be removed in a future release. I considered adding it to the documentation with a big warning to not use it - but decided against documenting it at all.
Regarding the timeout you experienced - because any SmartThings code (SmartApps or Device Type Handlers) execute within the SmartThings ecosystem along with other SmartApps or Device Type Handlers, there must be limits in place to the resources they use, so they do not negatively impact any other SmartThings code. That’s why they are only allowed to execute for a certain amount of time before being limited (we have work planned to document this).
Bottom line - use runIn(), not pause(). pause() will be removed soon. If you’re wondering exactly why pause() is unsupported (aside from the discussion of the execution model above), I am working to verify the specifics around this specific case and will communicate it soon (I don’t want to communicate possibly inaccurate information). I know I’m the kind of person who needs to know the why behind things
I hope my long-winded explanation doesn’t cause more confusion, I just wanted to shed some more light on this
More ST backend system resources are expended when a runIn() or runOnce() is used for times less than 5-10 secs IMHO since a running program using runIn() would need to be added to a ST startup queue, cleanup the running programs’ resources and then terminate. A new instance of the same program would be initiated almost immediately and re-consume global backend ST resources depending on the programs logic.
A programatic pause(), less than 5-10 seconds, IMHO would only consume minimal ST cloud services before resuming the program. I can see the reason why a long pause would not be acceptable and runIn() or runOnce() would be appropriate.
When/if ST ever enables local processing on the V2 hub, a pause() would be much easier to implement than a complicated runIn() or runOnce().
Also, ST cloud has been VERY UNSTABLE in the re-scheduling jobs recently, and many programs that critically depended on runIn() have not been re-initiated where as a short pause() would have worked perfectly.
@Jim Is there any documentation that mentions explicitly about Execution timed out after 40 units. I guess I wanted a clear understanding on whether it is bound to execution of a single function or just a single event which could result into executing of many functions. Also can you shed some light on metric “units” and what it means
I fear its the later, but as I will develop more of my code, Im afraid I this will hit me very hard.