Do unsubscribe() and unschedule() calls in tha app guarantee no more callbacks?

Is there a guarantee that when unsubscribe()/unschedule() method exist, there will be no more callbacks called in parallel, or after that (till next subscribe())?
If the callback was running in parallel to my call to unsubscribe()/unschedule(), it seems unsubscribe()/unschedule() methods should block inside untill the callback finishes.


Why would you expect that in a purely event driven environment? This is not a realtime operating environment. You should expect that once you call unsubscribe or unschedule, that anything currently running will run to completion, while at the same time your users UI isn't held hostage waiting on unnecessary blocking,

1 Like

It would be nice to have that, because we're in a multithreaded environment. Common pattern inside updated() is to unsubscribe(), make state changes, subscribe(). Now, if unsubscribe() does not guarantee that events are not going to call callbacks, it also means that while I'm updating the state, other threads can be reading it in parallel. And since state is not thread-safe, it's going to cause troubles.

Guarantee of stopping callbacks would make things somewhat easier.

I'm not sure how UI is depending on unsubscribe() call. If it does, I'm sure it's easy to change that (run updated() on a thread separate from UI or something like that).

Easier for who? And for what? I have written dozens of apps and drivers on Hubitat and SmartThings over the past 4 years and just cannot understand why people think they need these advanced constructs. Re-think your app. There is nothing that you need to create on this platform where you need to have absolute thread safety and deadlock protection. It's no different than SmartThings.

Re-think what it is you are trying to accomplish and design your app to fit the platform.

That statement is indicative that you probably should spend some time reading the documentation. The methods installed() and updated() are called by the system when the user first installs the app (clicks Done in the UI) or goes back into the app to update settings (clicks Done in the UI). Those are the entry points where you will need to set your event subscriptions and schedules. That method is called and the UI is not released until either installed() or updated() runs to completion. So yes, putting any kind of mutex protection on those methods or anything within them, could hang the UI indefinately.

Again, don't take this the wrong way, but before you worry about these advanced constructs, you should familiarize yourself with the basics of designing apps for this platform.


I'm sorry, could you clarify what you're saying here. Is it:

  1. You know of a way of writing correct code that does not have race conditions without using advanced constructs?
  2. Or that writing code with race conditions is fine, and I should not worry about it?

@bravenel, I was wondering if you could answer my original question.

What I am saying is that in a platform like Hubitat, for a consumer home automation system, if you are worrying about race conditions, you are doing something seriously wrong with your design. After writing more than 100 apps/drivers for Hubitat & SmartThings, I have yet to uncover a race-condition I couldn't solve using the tools available (i.e. atomicState w/ pauseExecution).

If you need those kind of abolutes, (microsecond accuracy across threads) for what you're trying to do, then you need a microcontroller as a middleman. So far you haven't shed any light as to what you are trying to do so the community can help. It seems you just want to criticize and complain.

Why not post some code samples you are trying to make work, and let the devs who are experienced with Hubitat help.


No, But read what @srwhite has to say. I agree with him. I too have written hundreds of apps and drivers for this platform, and this has NEVER been an issue. Your concern seems extremely theoretical. I'm a practical sort of person, and in this case don't really concern myself with theoretical problems. If and when some issue were to raise its head and move from theoretical to real, I'd spend some energy on it. In the meantime, that's pointless.


I was just trying to understand the programming model and not, as you nicely put it, "criticize and complain". I was just looking at some existing scripts before writing my own, so I don't have a specific problem at hand. I was hoping that asking questions was still OK in this community.

I also did not ask for "microsecond accuracy across threads". I'm pretty sure Java memory model can handle everything nicely, if used correctly.

1 Like

That's unfortunate. But thanks, I now see how things are here.

1 Like

I have experienced these issues in my MQTT app and driver and they took me by surprise but I have worked around them. atomicState helps immensely in apps but that is not available in drivers. state.var value updates I have given up relying on in drivers.

I enlisted help from pauseExecution and managed to alleviate the issues but that's somewhat inelegant from a programming and performance viewpoint. I now use a system of events and acknowledges and use attributes rather than state vars so it self paces and I try and detect concurrency and have a way to 'terminate' prior running instances of my app. It's not as I would like but it works.

I do feel we're patching around a fundamental issue and most of these things crop up during error or startup (MQTT broker disconnects with queued messages for example).

I think I'm fairly robust now but it has been a frustrating and unexpected consideration for app/driver design, with little documentation.

1 Like

I haven't seen your MQTT app, but did you ever think of enlisting a parent app as the gatekeeper for whatever time-critical messaging you were trying to manage? That would have unlocked access to atomicState and possibly helped to manage whatever synchronization challenges you were working though.

I use a standalone MQTT app with child devices but with a standalone MQTT driver. I started out parent/child and then changed to standalone for various reasons during my Groovy induction.

I am thinking about reverting to parent child, especially as I would like to implement multiple broker support but I have now resolved most issues so it will be an under the covers change rather than something fundamental. The division of connection intelligence and parsing messages between app and driver has always been evolving. A client device driver will cut down on event usage driver<>app and on reflection now is probably a better solution.

1 Like