haaska icon indicating copy to clipboard operation
haaska copied to clipboard

Improving the performance

Open unaiur opened this issue 7 years ago • 19 comments

Haaska lambda takes too long to process requests. I've stripped down all libraries, using only standard Python 3.7 libraries and I managed to reduce response time from 1106 milliseconds to 650 for cold start. For warm requests, I reduced it from 600 ms to less than 100ms.

Also, the implementation is much short and fits in a gist snippet: https://gist.github.com/unaiur/b354f986f874a8ca7ad80153d7b37440

I am using environment to configure the lambda. You need to create at least two environment variables: HOST=myname.duckdns.org BEARER_TOKEN=same_token_than_in_config_file

Also, you can add some optional configurations: POST=xxx (default 443) DEBUG=1 (debug is disabled by default)

unaiur avatar Apr 19 '19 18:04 unaiur

After debugging the lambdas with X-Ray, it seems that extra time comes from:

  • Initialisation time: <100ms vs 600ms. My lambda only loads 3KB, while yours uses more than 1MB because of the requests library.
  • Executing the lambda: first time it takes more or less the same, but my lambda reuses the connection in following invocations, allowing to reduce the execution time of a "discovery" request from 500 to 100ms. Of course, it depends on how far away is the AWS datacenter from you home. In my case, I am in Spain and AWS in Ireland (ping 50ms)

unaiur avatar Apr 19 '19 18:04 unaiur

Just on mobile so I can’t do too much yet, but if you’d like to make a PR, we’d be happy to review it.

I’ll admit, we’re using code that was originally a proof of concept with a few tweaks here and there to keep it working over the years.

If your version works well and doesn’t break compatibility with the config.json too much, I’m sure we can adopt it.

When you say it’s re-using the connection, just to be clear, it’s not keeping it open all the time, right?

We do want to keep an eye on what resources we use, as I would imagine a lot of users are on the AWS Free Tier.

anthonylavado avatar Apr 19 '19 20:04 anthonylavado

Actually, after I wrote that, the computer opened up, so I read over the code quickly. It looks pretty good. If all the config is moved over to Env Var, I’m okay with that. It shouldn’t be too much of a change, and it might even be easier to deal with any code upgrades, as now it doesn’t live beside the code explicitly.

As I said, let me know how you want to move ahead with it. As long as you’re okay with the same licensing (MIT), then I think we’d probably accept this pretty quickly.

anthonylavado avatar Apr 19 '19 20:04 anthonylavado

I am still analisyng what are the main latency sources. In my setup, it is:

  1. Lambda startup: ~~500ms~~ <50ms now
  2. DNS resolution using duckdns: ~200ms
  3. TLS handshake: 450ms. For some reason HA takes 250ms to answer client hello. I am diving deeper here.

unaiur avatar Apr 20 '19 15:04 unaiur

AWS does not kill lambda containers after serving a lambda invocation. The container is frozen and reused if a new request arrives soon enough (< 10 minutes usually). In that case, the connection is kept open and reused, and only closed on error or when the container is destroyed by AWS.

unaiur avatar Apr 20 '19 15:04 unaiur

Using AWS Route53 as DNS provider and setting up an NGINX proxy in front of HomeAssistant, I managed to reduce the cold latency to 300ms and the warm latency to 100ms. It seems that a Raspberry PI is too slow to handle TLS in Python.

unaiur avatar Apr 24 '19 23:04 unaiur

Will this be merged, it looks awesome! thanks @unaiur

Swiftnesses avatar May 18 '19 10:05 Swiftnesses

Most likely, I just haven't had much time to investigate the changes. But as it largely looks like dependencies it should be fine. @Swiftnesses have you been using it

mike-grant avatar May 18 '19 10:05 mike-grant

@mike-grant, not yet, but I plan to roll it out this weekend... Thanks for the great add-on BTW :)

Swiftnesses avatar May 18 '19 10:05 Swiftnesses

@unaiur Works perfectly! Thanks for this!

Redferne avatar May 22 '19 06:05 Redferne

@mike-grant: If I test this on the weekend and it works, I’m willing to PR it, merge it, and update the docs for the new env var steps.

Does that sound good?

anthonylavado avatar May 23 '19 04:05 anthonylavado

@unaiur thanks! I also replaced the original haaska and all the libraries it bundled, with this - and it worked fine. A lot simpler and lighter now. I removed all the libraries & stuff that were included in the old haaska.zip lambda 'bundle'. I had to customize line 54 (the URL 'path') since I use an NGINX reverse proxy with some custom path. The difference in responsiveness is very noticeable.

arigit avatar Jul 21 '19 05:07 arigit

+!, confirming. The gist snippet works just fine with the Python 3.7 libraries. Nice job.

LeapFrogSupport avatar Aug 07 '19 14:08 LeapFrogSupport

Hello I try to integrate the file but I can not possibly get the zip pack including the improvement? thank you in advance

Hydci avatar Sep 26 '19 09:09 Hydci

@unaiur I'm using your improved version for some time now and it is really fast. Thank you! For a few days now Alexa answers <devicename> does not respond

The invocation logs show the following error:

Traceback (most recent call last):
  File "/var/task/haaska.py", line 78, in event_handler
    return handle_event(event)
  File "/var/task/haaska.py", line 61, in handle_event
    headers = HEADERS)
  File "/var/lang/lib/python3.7/http/client.py", line 1252, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/var/lang/lib/python3.7/http/client.py", line 1298, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "/var/lang/lib/python3.7/http/client.py", line 1247, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "/var/lang/lib/python3.7/http/client.py", line 1026, in _send_output
    self.send(msg)
  File "/var/lang/lib/python3.7/http/client.py", line 987, in send
    self.sock.sendall(data)
  File "/var/lang/lib/python3.7/ssl.py", line 1034, in sendall
    v = self.send(byte_view[count:])
  File "/var/lang/lib/python3.7/ssl.py", line 1003, in send
    return self._sslobj.write(data)
BrokenPipeError: [Errno 32] Broken pipe

Is there something I can do on my end to fix this?

I'm running HA in docker behind an apache2 reverse proxy.

eifinger avatar Dec 09 '19 18:12 eifinger

Hi , I cleared all the code and pasted this one but i get error during test:

Response: { "errorMessage": "Handler 'lambda_handler' missing on module 'lambda_function'", "errorType": "Runtime.HandlerNotFound" }

itajackass avatar Mar 19 '20 22:03 itajackass

@unaiur @mike-grant was this change ever merged? Seems like a good improvement based on the discussion, but I didn't see the relevant commit.

dfederm avatar Apr 26 '20 18:04 dfederm

It hasn't been merged, I haven't really got around to reviewing the change unfortunately. @dfederm do you have time to make a pull request with these changes involved?

mike-grant avatar Apr 26 '20 18:04 mike-grant

Actually, I just found that the HA docs have a simplified set of instructions with an updated gist as well, similar to the one proposed here. I set up haaska a while back and at some point it stopped working (probably when the legacy api stuff was pulled?) so I was planning to dig into it tonight, but I'll just go that other route instead.

dfederm avatar Apr 27 '20 02:04 dfederm