-
-
Notifications
You must be signed in to change notification settings - Fork 302
Add async serialization support #1574
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |
| using JasperFx.MultiTenancy; | ||
| using MassTransit; | ||
| using Wolverine.Attributes; | ||
| using Wolverine.Runtime.Serialization; | ||
| using Wolverine.Util; | ||
|
|
||
| namespace Wolverine; | ||
|
|
@@ -120,6 +121,30 @@ public TimeSpan? ScheduleDelay | |
| get => _scheduleDelay; | ||
| } | ||
|
|
||
| public async ValueTask<byte[]?> GetDataAsync() | ||
| { | ||
| if (_data != null) | ||
| { | ||
| return _data; | ||
| } | ||
| AssertMessage(); | ||
|
|
||
| if(Serializer is IAsyncMessageSerializer asyncMessaeSerializer) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We use only when serializer support async |
||
| { | ||
| try | ||
| { | ||
| _data = await asyncMessaeSerializer.WriteAsync(this); | ||
| } | ||
| catch (Exception e) | ||
| { | ||
| throw new WolverineSerializationException( | ||
| $"Error trying to serialize message of type {Message.GetType().FullNameInCode()} with serializer {Serializer}", e); | ||
| } | ||
| } | ||
|
|
||
| return Data; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// The raw, serialized message data | ||
| /// </summary> | ||
|
|
@@ -132,10 +157,7 @@ public byte[]? Data | |
| return _data; | ||
| } | ||
|
|
||
| if (_message == null) | ||
| { | ||
| throw new WolverineSerializationException($"Cannot ensure data is present when there is no message. The Message Type Name is '{MessageType}'"); | ||
| } | ||
| AssertMessage(); | ||
|
|
||
| if (Serializer == null) | ||
| { | ||
|
|
@@ -144,7 +166,7 @@ public byte[]? Data | |
| _data = serializable.Write(); | ||
| return _data; | ||
| } | ||
|
|
||
| throw new WolverineSerializationException($"No data or writer is known for this envelope of message type {_message.GetType().FullNameInCode()}"); | ||
| } | ||
|
|
||
|
|
@@ -163,6 +185,14 @@ public byte[]? Data | |
| set => _data = value; | ||
| } | ||
|
|
||
| private void AssertMessage() | ||
| { | ||
| if (_message == null) | ||
| { | ||
| throw new WolverineSerializationException($"Cannot ensure data is present when there is no message. The Message Type Name is '{MessageType}'"); | ||
| } | ||
| } | ||
|
|
||
| internal int? MessagePayloadSize => _data?.Length; | ||
|
|
||
| /// <summary> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |
| using Wolverine.ErrorHandling; | ||
| using Wolverine.Logging; | ||
| using Wolverine.Runtime.Handlers; | ||
| using Wolverine.Runtime.Serialization; | ||
| using Wolverine.Transports; | ||
|
|
||
| namespace Wolverine.Runtime; | ||
|
|
@@ -106,7 +107,7 @@ public async Task InvokeAsync(Envelope envelope, IChannelCallback channel, Activ | |
| } | ||
| } | ||
|
|
||
| public bool TryDeserializeEnvelope(Envelope envelope, out IContinuation continuation) | ||
| public async ValueTask<IContinuation> TryDeserializeEnvelope(Envelope envelope) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Method signature is changing - for me it is even better because it is more function like - one result instead two (bool and IContinuation) |
||
| { | ||
| // Try to deserialize | ||
| try | ||
|
|
@@ -127,49 +128,52 @@ public bool TryDeserializeEnvelope(Envelope envelope, out IContinuation continua | |
|
|
||
| if (_graph.TryFindMessageType(envelope.MessageType, out var messageType)) | ||
| { | ||
| envelope.Message = serializer.ReadFromData(messageType, envelope); | ||
| if (serializer is IAsyncMessageSerializer asyncMessageSerializer) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We use async if it implement this |
||
| { | ||
| envelope.Message = await asyncMessageSerializer.ReadFromDataAsync(messageType, envelope); | ||
| } | ||
| else | ||
| { | ||
| envelope.Message = serializer.ReadFromData(messageType, envelope); | ||
| } | ||
| } | ||
| else | ||
| { | ||
| continuation = new NoHandlerContinuation(_runtime.MissingHandlers(), _runtime); | ||
| return false; | ||
| return new NoHandlerContinuation(_runtime.MissingHandlers(), _runtime); | ||
| } | ||
|
|
||
| if (envelope.Message == null) | ||
| { | ||
| continuation = new MoveToErrorQueue(new InvalidOperationException( | ||
| return new MoveToErrorQueue(new InvalidOperationException( | ||
| "No message body could be de-serialized from the raw data in this envelope")); | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| continuation = NullContinuation.Instance; | ||
| return true; | ||
| return NullContinuation.Instance; | ||
| } | ||
| catch (Exception? e) | ||
| { | ||
| continuation = new MoveToErrorQueue(e); | ||
| return false; | ||
| return new MoveToErrorQueue(e); | ||
| } | ||
| finally | ||
| { | ||
| Logger.Received(envelope); | ||
| } | ||
| } | ||
|
|
||
| private Task<IContinuation> executeAsync(MessageContext context, Envelope envelope, Activity? activity) | ||
| private async Task<IContinuation> executeAsync(MessageContext context, Envelope envelope, Activity? activity) | ||
| { | ||
| if (envelope.IsExpired()) | ||
| { | ||
| return Task.FromResult<IContinuation>(DiscardEnvelope.Instance); | ||
| return DiscardEnvelope.Instance; | ||
| } | ||
|
|
||
| if (envelope.Message == null) | ||
| { | ||
| if (!TryDeserializeEnvelope(envelope, out var serializationError)) | ||
| var deserializationResult = await TryDeserializeEnvelope(envelope); | ||
| if(deserializationResult != NullContinuation.Instance) | ||
| { | ||
| activity?.SetStatus(ActivityStatusCode.Error, "Serialization Failure"); | ||
| return Task.FromResult(serializationError); | ||
| return deserializationResult; | ||
| } | ||
| } | ||
| else | ||
|
|
@@ -180,11 +184,11 @@ private Task<IContinuation> executeAsync(MessageContext context, Envelope envelo | |
| if (envelope.IsResponse) | ||
| { | ||
| _runtime.Replies.Complete(envelope); | ||
| return Task.FromResult<IContinuation>(MessageSucceededContinuation.Instance); | ||
| return MessageSucceededContinuation.Instance; | ||
| } | ||
|
|
||
| var executor = _executors[envelope.Message!.GetType()]; | ||
|
|
||
| return executor.ExecuteAsync(context, _cancellation); | ||
| return await executor.ExecuteAsync(context, _cancellation); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,5 +7,5 @@ public interface IHandlerPipeline | |
| { | ||
| Task InvokeAsync(Envelope envelope, IChannelCallback channel); | ||
| Task InvokeAsync(Envelope envelope, IChannelCallback channel, Activity activity); | ||
| bool TryDeserializeEnvelope(Envelope envelope, out IContinuation continuation); | ||
| ValueTask<IContinuation> TryDeserializeEnvelope(Envelope envelope); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is only one potential breaking change but I'm wonder if this interface should be public? Maybe it should be internal or nobody is executing this so event public we don't break anything
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should not be part of the public interface. It's just a detail of the HandlerPipeline details
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jeremydmiller So I think it should be no problem with change :) As a note in our company we use MS https://www.nuget.org/packages/Microsoft.CodeAnalysis.PublicApiAnalyzers/ to keep public API stable. It reminds to keep internal things (when things are internal your life is easier because analyser is not screaming in your face :) ). You have to use to this analyser especially when adding new API but tooling is quite good (especially "use this for whole project/solution" so you can add new API's in one click. |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,4 +14,14 @@ public interface IMessageSerializer | |
| object ReadFromData(byte[] data); | ||
|
|
||
| byte[] WriteMessage(object message); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Async version of <seealso cref="IMessageSerializer"/> | ||
| /// </summary> | ||
| public interface IAsyncMessageSerializer : IMessageSerializer | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We extend standard serializer so nothing is changing in code - envelope serializer type is still IMessageSerializer |
||
| { | ||
| ValueTask<byte[]> WriteAsync(Envelope envelope); | ||
|
|
||
| ValueTask<object?> ReadFromDataAsync(Type messageType, Envelope envelope); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is additive change GetDataAsync can be executed and it fallback to Data