vlingo / xoom-symbio

The VLINGO XOOM platform SDK delivering Reactive storage that is scalable, high-throughput, and resilient for CQRS, Event Sourcing, Key-Value, and Objects used by services and applications.
https://vlingo.io
Mozilla Public License 2.0
40 stars 9 forks source link

Implement Storage for DynamoDB #2

Closed kmruiz closed 6 years ago

kmruiz commented 6 years ago

WIP -> Solves issue #1

This is a basic implementation of a DynamoDB state store using the asynchronous DynamoDB client.

Notes

Current State

Please, give some feedback if you find any issues on the current implementation.

VaughnVernon commented 6 years ago
kmruiz commented 6 years ago

Hi Vaughn!

Actually DynamoDB dependencies are all of them but the SDK are for testing purpouses only :D :

Surprisingly is quite fast to download everything.

I have several questions about how to implement the Dispatchable state persistence:

And I have some 'convention' questions :D.

Thanks for your help!

kmruiz commented 6 years ago

I would say that, by now, I could considered it usable:

Is there anything left to ensure that is working?

VaughnVernon commented 6 years ago

@kmruiz I missed a few of your questions:

What should I do if TypeVersion is different? Is there any way to call a migration on the state?

Currently there is no specific migration tools and the differences are left to the application developer to work out the mappings. There will likely be additional tooling provided to help with this, but most of the heavy lifting will still rest on the developer's shoulders.

Needs the persistence actor to implement DispatcherControl?

Yes. The implementation must remove/delete the Dispatchable from storage when it receives confirmDispatched() and also arrange for all unconfirmed to be re-dispatched when dispatchUnconfirmed() is received.

Dispatchables should be sent in order of arrival or order of persistence?

I think it depends on the projection implementation, and thus you should offer the parameterized option to operate either sync or async. Still, the Dispatcher and Projection should not count on total ordering and/or exactly-once delivery because there could be redelivery caused by slow/failed confirmation, for example. So every kind of sensitive projection should be an idempotent receiver.

kmruiz commented 6 years ago

Hi! Sorry for the late answer!

I think there are three things left for considering this PR done (correct me if I'm wrong):

VaughnVernon commented 6 years ago

Yes, I agree, but just a few clarifications seem appropriate.

  1. The idea of the BinaryStateStore is that you write and read byte[]. So you could serialize JSON to bytes, but it would be more like storing a Protobuf serialization. If you mean to use JSON as bytes just for testing, that's fine of course. Did I understand you correctly?

  2. I have already changed NullState to parameterized NullState<T> and provided states:

public static NullState<byte[]> Binary = new NullState<>(EmptyBytesData); public static NullState<String> Text = new NullState<>(EmptyTextData);

I also added a method to the ReadResultInterest:

void readResultedIn(final Result result, final Exception cause, final String id, final State<T> state);

And also to WriteResultInterest:

void writeResultedIn(final Result result, final Exception cause, final String id, final State<T> state);

So now you can write code such as:

} catch (Exception e) {
  interest.writeResultedIn(Result.Error, e, state.id, state);
}

And like this:

if (storeName == null) {
  final String message = "No store mapping for " + type.getName();
  interest.readResultedIn(Result.NoTypeStore, new IllegalStateException(message), id, NullState.Binary);
}

Makes sense?

kmruiz commented 6 years ago

Makes totally sense, actually was the exact part that I was missing for Read/WriteResultInterest. About using Protobuf for the BinaryStore, I think it's a good idea, I can implement it :D.

Thanks for your help!

VaughnVernon commented 6 years ago

Excellent, thanks! Also you had some comments about adapting/migrating from one data version to the next. I have some experience with that, and also some ideas. Still, I would like to know what your ideas are, so please share what you have in mind.

kmruiz commented 6 years ago

Hi!

I've been looking at the documentation of Protocol Buffers:

https://developers.google.com/protocol-buffers/docs/javatutorial

And seems that you need to generate code to make it work and it highly depends on the class that you want to persist. It will generate a class, builders and some serialization code.

I was thinking maybe it's a better idea to use something like MessagePack:

https://msgpack.org/index.html

It's tiny and easy to parse. What do you think?

This is the only thing left to merge this PR.

And about migrations, it's a big topic :D and it doesn't affect only DynamoDB but all persistences, maybe we can create an issue and discuss it there. What do you think?

VaughnVernon commented 6 years ago

All good, thanks!

Regarding binary store testing, you don't need Protobuf or MessagePack. I thought you were in need of using a reliable binary serialization tool for a project using vlingo-symbio. For testing it's much easier.

You can just convert a String to byte[] as is done here. After you write and then read, you can assert the binary read state against the write state.

When you are ready for merge please comment and I can then merge your work.

kmruiz commented 6 years ago

When the build is confirmed to be green, it's ready to be merged :D.

kmruiz commented 6 years ago

Seems that the InMemoryPersistence test somehow had a timeout. I'm going to push an empty commit to run the build again.

VaughnVernon commented 6 years ago

@kmruiz You can navigate here and restart the build.

kmruiz commented 6 years ago

Good to know! I didn't see the option :D! Now everything is green!

VaughnVernon commented 6 years ago

@kmruiz Are you ready for a merge or would you prefer doing more work on the binary store before the merge?

kmruiz commented 6 years ago

@VaughnVernon IMHO it can be merged, I would like to refactor the implementation of record adapters, to reuse more code, but it's a safe refactor that can be done later.