rebus-org / Rebus.SqlServer

:bus: Microsoft SQL Server transport and persistence for Rebus
https://mookid.dk/category/rebus
Other
43 stars 42 forks source link

Make saga serializer configurable #59

Closed mathiasnohall closed 3 years ago

mathiasnohall commented 4 years ago

if I use the configurationbuilder like so:

.Serialization(s => s.UseNewtonsoftJson(JsonInteroperabilityMode.PureJson))

the objectserializer still uses json with full type information. i.eg. when persisting saga data to the sql database in SqlServerSagaStorage.cs

the NewtonsoftJsonConfigurationExtensions should register an instance of ObjectSerializer wich honors the purejson interopability

mookid8000 commented 4 years ago

It's because .Serialization(s => s.UseNewtonsoftJson(JsonInteroperabilityMode.PureJson)) configures message serialization and not saga serialization.

The saga persister for SQL Server just happens to use JSON with full type information to store sagas, which makes it possible to support inheritance, references to objects via interfaces/abstract base classes, etc.

Do you have a problem with the fact that the serialized data contains type information?

mathiasnohall commented 4 years ago

Hi!

yes I realized that after digging more into the source code. thanks!

It was not super obvious that the configurationbuilder for json settings only applied to rabbitMQ serialization.

yes, the problem for us is that we have an e-commerce platform which handles saga data over a long period of time. i.eg. when the warehouse finishes packing an order. So we have long living sagas. And in our rapid development cycle we cannot do any changes in sagadata that changes typenames during that time when the saga is live in the database. This has happened frequently that rebus cannot deserialize saga data if we have made any changes on namespaces in our sagadata.

one preferable solution would be to be able to change the serializer in the same way as you can do with the rabbitMQ serializer. And perhaps store master saga object typename in some kind of metafield in the database.

Thanks!

mookid8000 commented 4 years ago

Hi @mathiasnohall , sorry for taking so long to get back to you.

The question of how to store saga data depends on which saga persister is used. The SQL persister happens to JSON serialize the data, but e.g. the MongoDB persister will use its built-in BSON serializer to store it.

Therefore, this particular issue is not really a Rebus core issue. I'll move this issue to Rebus.SqlServer and change it to be about making the serializer configurable. I hope that makes sense to you 🙂

mookid8000 commented 4 years ago

The SQL saga persister will serialize data using Rebus' built-in ObjectSerializer, which is full of type information.

While this is convenient to be able to reliably roundtrip objects involving inheritance hierarchies and stuff, it's not really well-suited for long-lived saga data, as it makes refactoring the saga code harder.

Therefore, it would be nice if the saga data serializer could be configured.

The API should probably be changed so that something like the following could be done:

Configure.With(...)
    .(...)
    .Sagas(s => {
        s.StoreInSqlServer(...)
            .SerializeSagaDataWith(new MyCustomSagaDataSerializer());
    })
    .Start();

which requires that StoreInSqlServer returns a SagaConfigurationCustomizer that can be used for further customizations.

mookid8000 commented 3 years ago

Fixed by #77