-
Notifications
You must be signed in to change notification settings - Fork 36
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
Provide entity support for direct grpc connections to DTS #369
base: main
Are you sure you want to change the base?
Conversation
…on history events, as used by DTS, and enable entities by default when using DTS backend.
7f3fc0a
to
8db3603
Compare
I am marking this as ready for review now that I have some tests passing. Given that iterations are slow, I want to run a lot more tests before merging though. |
LGTM |
… of failure details
@@ -85,6 +85,12 @@ static void ConfigureSchedulerOptions( | |||
.Configure(additionalConfig ?? (_ => { })) | |||
.ValidateDataAnnotations(); | |||
|
|||
builder.Services.AddOptions<DurableTaskClientOptions>(builder.Name) |
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.
I think there is a builder.Configure(optionsCallback)
overload you can use
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.
yes, much better.
/// automatically converted back and forth between the old DT Core representation (JSON-encoded external events) | ||
/// and the new protobuf representation (explicit history events), which is used by the DTS scheduler backend. | ||
/// </summary> | ||
public bool ConvertOrchestrationEntityEvents { get; set; } |
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 value and InsertEntityUnlocksOnCompletion
look like they are more implementation details and not a public API. I would prefer we figure out a way to make these non-public if possible. If this must be public due to different projects, then we should find a way to hide this in an .Internal
namespace and add comments declaring this not meant for public consumption.
Here is an example: https://github.com/microsoft/durabletask-dotnet/blob/main/src/Abstractions/Internal/IOrchestrationSubmitter.cs
One idea would be to make these properties internal
(maybe even in a sub-class to keep them together). Then add an extension method ConfigureForAzureManaged(this GrpcDurableTaskWorkerOptions options)
under Microsoft.DurableTask.Worker.Grpc.Internal
namespace with the comments. Then AzureManaged can call that.
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.
Would it be possible to use an "internals visible to" property so that only Worker.AzureManaged can access these options?
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.
Yes, you can do that for now. I did it in the Abstraction package:
Please just add a comment saying these are used by AzureManaged to treat them as public API breaking change rules
But I have since changed my stance on how much I like that (I don't recommend it anymore). The reason is this can still cause issues down the road. If customers use Worker.AzureManager/1.n
which uses these cross-assembly internal
properties, but also use Worker.Grpc/1.n+1
which has since removed these properties in a refactor, the app will throw method missing exceptions.
BUT given we already use this pattern in the code base, I think the comment will be good enough. Maybe in a v2.x we can rethink and remove this approach.
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.
I tried the "internals visible" approach and it worked but it is also causing some warnings (because there are conflicts between doubly defined classes, those come from files that are shared between the projects).
So I will instead do what you suggested before.
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.
I have modified the code so it now uses a private class InternalOptions
, and offers a public extension method ConfigureForAzureManaged(this GrpcDurableTaskWorkerOptions options)
like you suggested.
/// Configure the worker to use the default settings for connecting to the Azure Managed Durable Task service. | ||
/// </summary> | ||
/// <param name="options">The gRPC worker options.</param> | ||
public static void ConfigureForAzureManaged(this GrpcDurableTaskWorkerOptions options) |
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.
Can this be moved to the AzureManaged
project? Code in the Grpc
project is supposed to be backend-agnostic.
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 based on a suggestion of mine. The properties being added in InternalOptions
are specialized for AzureManaged scenario, but they need to be in the project. To avoid having these options that customer's are not expected to ever configure, we make the values themselves internal
and only expose a single public
point to configure them.
With that said, we can name this method more backend-agnostic, but it does need to remain in this project so it can access the internal properties. Additionally, we should include a disclaimer in the XML doc explaining this is considered an internal API surface and not subject to breaking change guarantees.
|
||
// The point of this class is to reverse a Newtonsoft serialization that happened in prior DT code. | ||
// To do this reliably we use the same Newtonsoft. | ||
// This is not introducing a new dependency, and should be eliminated once the original dependency is eliminated. |
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.
Just to be clear, if we remove the DT.Core dependency from this SDK, will that also allow us to remove this dependency on Newtonsoft.Json?
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.
Yes. The point of this class is to "undo Newtonsoft serialization" that was unfortunately already done inside DT.Core. So the Newtonsoft dependency goes away when either (a) Newtonsoft dependency is removed from DT.Core, or (b) DT.Core dependency is removed.
@sebastianburckhardt you'll need to rebase this PR on the latest from main. We no longer use submodules for updating the protobuf definitions. See this change: #370. |
using System.Collections.Generic; | ||
using System.Text; | ||
|
||
namespace Microsoft.DurableTask.Worker.Grpc.Internal; |
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.
Please move to an Internal
folder.
/// Options for controlling backend-specific features. These are not exposed directly, but can be accessed via | ||
/// the extension methods in <see cref="Internal.InternalOptionsExtensions"/>. | ||
/// </summary> | ||
class InternalOptions |
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.
Consider doing one of the following:
- Make this a nested class in
GrpcDurableTaskWorkerOptions
. - Or, rename to
InternalWorkerOptions
and move toInternal
folder (along with the extension class for it).
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.
I am making this a nested class.
/// unlock events into the history when an orchestration terminates while holding an entity lock. | ||
/// </summary> | ||
public bool InsertEntityUnlocksOnCompletion { get; set; } | ||
internal InternalOptions InternalOptions { get; set; } = new(); |
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.
I recommend removing the setter (unless it is needed)
internal InternalOptions InternalOptions { get; set; } = new(); | |
internal InternalOptions InternalOptions { get; } = new(); |
eng/proto
Outdated
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.
I thought this was removed
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.
Will merge second-to-latest commit in main which introduced the vendor pattern.
/// <summary> | ||
/// Provides access to configuring internal options for the gRPC worker. | ||
/// </summary> | ||
public static class InternalOptionsExtensions |
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.
Please include disclaimers as seen on this type: https://github.com/microsoft/durabletask-dotnet/blob/main/src/Abstractions/Internal/IOrchestrationSubmitter.cs
Co-authored-by: Jacob Viau <[email protected]>
Co-authored-by: Jacob Viau <[email protected]>
implements the necessary protocol conversions and configurations for providing entity support when connecting a DTS backend directly ("portable SDK").