question

Kay Lerch avatar image
Kay Lerch asked

Powerful Alexa Skills Kit extensions for state management (Java)

Dear community,

I am developing skills for Alexa since four months now and really had my bad times with state persistence and state management in my skills. What I've done in the last weeks was to build an SDK for having this done in just a few lines of code. Recently I open-sourced my project. It's got an extensive documentation so feel free to dive into details:

https://github.com/KayLerch/alexa-skills-kit-states-java

The SDK is an extension for the Skills Kit for Java and it hides all the complexities with saving state to your session or to DynamoDB. It even got a handler for saving state in S3 buckets and provides a framework for letting you build your own state handlers.

The SDK is capable of saving state of POJO models in different scopes (Session, User, Application).

I am really curious of what you think and if you would use it for your own projects.

With some feedback and a bit more testing I plan to publish it in central Maven repo.

Best,

Kay

alexa skills kitalexasdk
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

jjaquinta avatar image
jjaquinta answered

Hey Kay. That's a nice start. What it seems to be missing is caching look ups and backgrounding saves. Those are features that really increase the response time to users and save on DynamoDB charges. You might want to cross reference the skill I posted as an example of complex Alexa architecture and design. (Also won 3rd place in the Hackster.io contest.) There's a comprehensive video included (45 minutes) going into how to tackle large, complex projects with Alexa. It's all open source (Apache). So if you were looking for a high end example to show off your framework for, you are welcome to take it, modify it, and post it as a reference example.

10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Kay Lerch avatar image
Kay Lerch answered

Hey jjaquinta,

thanks for your feedback. Maybe you can give more detail on what you mean by "caching look ups" and "backgrounding saves"? The SDK let's you easily save retrieved state from Dynamo to the session in order to decrease overall reads to the data store.

I know your skill and like it. It looks like a complex scene and good reference for newbies.

Btw: It was my skill winning that contest :) The Morse coder skill will have a major update in the next weeks and I will apply my SDK extension for all the session handling. So far my skill has a lot of boilerplate for doing really trivial things for its state management.

https://github.com/KayLerch/alexa-morse-coder (the beta for next version)

Best, Kay

6 comments
10 |5000

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

jjaquinta avatar image jjaquinta commented ·

By "saving retrieved state from Dynamo to the session" do you mean in the JSON transaction with Alexa? I usually advise people to avoid using session variables serialized by the transaction service. Alexa drops the conversation way too often for that to be a reliable method of caching. However, if you are working with Lambda, that's just about the only choice you have since it destroys your JVM between calls.

What I mean by "caching look ups" is that after a dynamo db look up is done, and the POJO deserialized, it is stored in global memory via a key. The next time that object is requested, the code checks if it has a copy in global memory, and if so, it retrieves that. The simplest implementation would use a HashMap. Since that has no expiry, the next simplest uses a WeakHashMap. That empties as soon as the object is no longer referenced. But that may be too quick. The Cadillac approach would be a hybrid object which keeps a hard-reference to each object, and then changes it to a weak reference after a set amount of time or when too much memory is used. I do that in StarLanes. I can't remember if I exposed that code in SubWar or not.

0 Likes 0 ·
Kay Lerch avatar image Kay Lerch jjaquinta commented ·

These are valid points but not feasible in a stateless runtime like a Lambda function. There's no global memory in a serverless environment. An SDK relying on system resources would be incompatible with Lambda functions - in which most skills run.

Interesting fact with the unreliable session persistence (yes, I mean the JSON transaction). The SDK let you do both, persisting permanent state from DynamoDB into the JSON for caching it, but also to read/write from DynamoDB/S3 without leveraging the session JSON.

As you point out performance is key for speechlet handlers, so the session JSON is the only way to "cache" information with Lambdas. For my skill I am only caching session-related information (like what was the last question asked) but push important information to DynamoDB immediately (like the user score).

This is an interesting discussion. Thanks for being my counterpart ;)

0 Likes 0 ·
jjaquinta avatar image jjaquinta commented ·

By "backgrounding saves" which I men is that when the "save POJO" function is called, it puts the object to be saved on a queue. (Well, first it checks to see if the object is already on the queue.) A background thread runs every so often, goes through each object on the queue, saves and removes it. The advantage of this is that saves do not block the thread that returns to the user. For 2-3 dynamo db transactions, this can shave up to a second off of your response time, which is significant. The other advantage is that you can be "sloppy" and request a save of your POJOs each time they are modified, instead of setting a "changed" flag and calling save just once. You could probably even put it on your "set" functions. This can then interoperate with your lookup cache. Effectively as long as an object is on the write queue, it can be considered to also be in the read cache.

I thought your Morse coder skill demonstrated a good breadth of Alexa functionality, and I congratulate you on that. I hope that for your next effort you turn your talent to skills that have a wider focus and appeal to Alexa users. The skills tab could very much use a wider selection of comprehensive skills of wide interest and less narrow focus niche skills. At least in my opinion.

0 Likes 0 ·
Kay Lerch avatar image Kay Lerch jjaquinta commented ·

I admit that in a steady runtime solving tasks asynchronously is really much what you want for e.g. pushing data to DynamoDB. However, a Lambda function is no good place for doing this. Once again, the SDK aims for being your mate in Lambda-skills. A Lambda execution won't wait for asynchronous tasks to be completed. Even if they would it's useless in regards to better performance.

It's still true you have to be careful what you do with that SDK (or with db transactions at all). One downside of abstraction is it lacks of transparency to what is a serverside action.

What really has room for improvement is to avoid pushing data in case of an unchanged POJO model. Let's see what I can do with Observables.

Best, Kay

0 Likes 0 ·
jjaquinta avatar image jjaquinta Kay Lerch commented ·

People use Lambda because it is cheap and easy, not because it is a good solution. I tried it, but found it too lacking to do professional skills with. There's no room to grow a simple skill into a more advanced one. As soon as you start wanting to do more database transactions the latency gets to be too much. What would make this a game changer is if you could do both. Run the library in "lambda mode" or run it in "web service" mode. Then you would have a tool that would get past that problem. People could start with "cheap and easy", and as their needs grew, they would have an easy migration path to a more powerful platform. SubWar isolated all of its I/O behind a service class. You could create or instantiate a different service class depending on your persistence model. That might be an approach for you to use.

0 Likes 0 ·
Show more comments