Homeyscript memoryleaks

Every couple of seconds, as data comes in over MQTT. Does that matter? Leaking shouldn’t happen anyways, and I don’t think there’s anything in the script that leaks. If so, how can I avoid that?

Just wondering, your script doesn’t have an obvious memory leak but it’s perfectly possible that the Homeyscript app implementation itself is leaking. So might be interesting running a test to see if I can reproduce it.

It’s not HomeyScript itself @ my setup
To help, I’ll try calling a script every sec, which writes to a tag, to see if the memory use increases.

Edit Not reproduceable with my script mentioned; memory useage increases to max 25MB’s during test.
I’ll let it run to see what happens after a few days.

Thanks. As you can see from my graph, memory usage stays fairly constant for a long time, then makes a fairly large jump. Earlier tonight it went high enough that Homey stopped Homeyscript, so I had to restart it to get back going.

As others have suggested earlier, a workaround is to just create a flow that resets Homeyscript, either on a regular basis or by some monitoring function.

I would love if there was something I could do to the script(s) to fix this, but I simply can’t understand how these very simple scripts could leak memory. And also, if they did, why doesn’t memory usage simply climb gradually over time? After all, the scripts are called tens of thousands of times every day.

Can’t you use something like a Logic variable and some {{ … }} magic to do what you now do with your script? I bet that if you ask Athom why your script it acting that way, you’ll get the answer that Homeyscripts aren’t supposed to be called that often.

Perhaps. I’m not sure. What I am doing, is to send incoming values from MQTT to a virtual sensor device. There is an app (MQTT Hub) that I could probably use, but that feels like overkill for the simple task at hand. I have a flow that triggers when the MQTT client receives a message on a specific topic, and then runs my script with that message as the argument, and the script converts that message (which is a number in a string) to a real number tag (which for some topics will be a floating point value, and for others an integer) which is fed into the virtual sensor.

Can I easily do this with just some {{ … }} magic?

The flow looks like this:

I am also feeding the converted value to another app, as you can see. The delays was added just because order of execution is not deterministic, so I had to ensure that the script had been run before the tag was used.

I have asked for support from Athom, but I haven’t had any feedback yet. If their response is what you say, I’d be somewhat surprised. The Homey is a computer, and doing stuff over and over again should be no problem, unless there is a inherent design issue with their internal architecture.

It sounds like the MQTT Hub app, specifically its “MQTT Device” driver, fits what you want.

Even though Homey is a computer, it’s isn’t meant to be a generic one. Homeyscript is a nice feature, but I doubt that it has been tested extensively and it wouldn’t surprise me if calling it as often as you do will expose issues with its implementation (like memory leaks). But again, I also doubt that Athom would be willing to fix them (also because debugging apps is a PITA on Homey).

Yes, the MQTT Hub app will probably do what I want, but as I said, it is somewhat overkill for the very small task at hand. I take it you don’t see a way of using some {{ … }} construct to solve my problem?

It is a pity that debugging apps is a PITA on Homey, I don’t think I fully realized that before jumping onboard with Homey.

It’s probably possible, I just haven’t bothered to try it :sweat_smile:Probably something like {{ round([Message received from topic]) }} is enough for both the “Set virtual sensor value” and “Update consumption with” cards.

1 Like

Thanks, but that doesn’t seem to work. Probably doable though, so I’ll just have to experiment some more.

Looked at it some more, and this works:

{{number('Message received from topic'
)}}

Message received from topic is the tag provided by the MQTT client.

Thanks a bunch, I can now get rid of my scripts, which is good, but shouldn’t have been necessary.

2 Likes

FWIW firing a script every sec does increase the memory usage more and more.
End of test.

1 Like

Time to post an issue here: Issues · athombv/com.athom.homeyscript · GitHub

1 Like

Thanks for confirming! As you can see, my problem was solved by getting rid of my scripts (with the help of @robertklep), but it is if couse still not acceptable that Homeyscript leaks memory.

1 Like

I see that there are still a lot of people with memoryleak problems. Since i started this post i want to share how i solved it.

The problem in my situation was that i had a lot of scripts using asynchronous methodes without awaiting them. I solved the memoryleak problem by awaiting these calls.

As a example You could modify a betterlogic variable this way:

bl.apiPut('varname/' + newvalue);

But this wil result in a memoryleak. Use await to avoid that:

await bl.apiPut('varname/' + newvalue);

if you want to read a value, you can do this:

bl.apiGet('varname').then(variable => {
   ...
   ...
}

This also gives a memoryleak. use instead:

const variable = await bl.apiGet('varname')

if you want to execute multiple asynchronous methodes at ones, use Promise.all:

const proms = [
    bl.apiGet('varname1'),
    bl.apiGet('varname2'),
    bl.apiGet('varname3'),
]
const [value1, value2, value3] = await Promise.all(proms);

If you need to excecute some code after some time, you could use:

wait(10000).then(_ => {
  ...
  ...
})

This will also result in a memoryleak. You can better use:

await wait(10000)
...
...

or:

await wait(10000).then(_ => {
...
...
})

But always use await for ALL asynchronous calls

This is also true for nesting asynchronous calls:

await wait(10000).then(async _ => {
 const variable = await bl.apiGet('varname')
})

If you absolutely need to use a asynchronous call without await, you can try to trigger the garbage collector inside the then.

wait(10000).then(_ => {
 ...
 ...
 ...
 gc();   // calll the garbage collector
})

But i’am not sure if it will help and also the garbage collector is very cpu heavy

Have you notified Athom about this? They should know that, apparently, promises leaks memory in Homeyscript.

How did you check that memory leaks with one method of handling promises, but not the other?

I have first tried to refactor my scripts. Since i used fetch in many scripts i replaced fetch with Homey.flow.runFlowCardAction with uri: ‘homey:manager:logic’ but that did not solve the memoryleak. Also did other things but nothing helped.

Then i noticed that i used all sync calls waithout await. As far as i know using await is not mandatory but changed some heavely used scripts and this resulted in much less memory leaks. I then refactored all scripts wich solved the memoryleak completely

Someone on Homey’s Slack channel also noticed that the memory leaks that they were experiencing were gone after a recent firmware update, so it may also be related to that.

maybe. Users still having memoryleak problems should try it.
But personaly i don’t think it is firmware related. I think it is a problem with Homeyscript

Could very well be, therefore it would be useful to tell Athom about it :smiley: