-
Notifications
You must be signed in to change notification settings - Fork 517
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
Add compat mode option to AzureClient and TinyliciousClient #20997
Conversation
⯅ @fluid-example/bundle-size-tests: +424 Bytes
Baseline commit: b47f044 |
@@ -15,6 +15,9 @@ import { IFluidLoadable } from '@fluidframework/core-interfaces'; | |||
import { IRuntimeFactory } from '@fluidframework/container-definitions/internal'; | |||
import { ISharedObjectKind } from '@fluidframework/shared-object-base'; | |||
|
|||
// @public | |||
export type CompatMode = "1" | "2"; |
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'd make it an object / interface, not a string.
We will need to expose various options (like compression knobs) as our customers (like Autodesk) will ask for it.
There is no better place to do it other than here, on an object that is unique to a compat mode.
In other words, it should not be possible (should be compile error) for users to attempt to set or change compression settings for "1" schema as it does not apply / does not exist at that level of compatibility.
Same in reverse - when/if we remove ability some of these knobs in the future (let's say in 3.0 compat mode), ideally it should be a compile break for users do change these knobs on config that no longer allows that.
I also think it's more readable if it says { compatLevel: "1" } over "1" (even though more verbose).
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.
My intention is to disallow nuanced configuration here - in the sync we agreed this feature is purely about migrating from 1->2, not for configuring other accessory features. Those features should design and establish their own appropriate API surface to enable/disable/customize.
E.g. GC uses the MonitoringContext to enable, or summaryCompression is offered on AzureClientProps. There might be better options available for how to do it and we can certainly discuss, but it's a separate scope from the primary concern of safely getting customers from 1->2.
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 these are not great examples (there is no overlap with compat settings).
Let's play the game in reverse - let's assume there is already compression setting out there and you are adding this PR. What would you do if user specifies compression and V1? Would it throw UsageError()? Let it use compression despite user saying - use compatibility mode?
At extreme, we will have all options in two places - one controlled from here, and one controlled from their respective knobs. Is this good API to have?
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.
Given significantly complicated compat story and upgrade paths, I generally do like the idea to simplify and constrain in this case. Simplify: if the features are tightly coupled, offer them through unified APIs. Constrain: User should have very limited and explicit means to toggle/config anything related to our incompatible features.
minimumBatchSizeInBytes: Number.POSITIVE_INFINITY, // disabled | ||
compressionAlgorithm: CompressionAlgorithms.lz4, | ||
}, | ||
// TODO: Include explicit disables for things that are currently off-by-default? |
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.
FYI - I merged #20604 that impacts choices here.
Yes, I'd explicitly mention all the settings here, as they should not change over time (though it's hard to enforce that for future settings that are not known at this time).
Ideally, we have tests that help us finding non-compat settings in the future, and thus force adding new things here (for example, such test should break once #20604 is picked up).
Might be useful reference point: filterRuntimeOptionsForVersion()
* Valid compat modes that may be specified when creating a DOProviderContainerRuntimeFactory. | ||
* @public | ||
*/ | ||
export type CompatMode = "1" | "2"; |
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.
Is the intent to hide away details about the differences between the versions? If so, the type union makes sense to me. If not, an enum-like object would give us a place to document implications of each version.
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.
That pattern would also discourage the use of magic constants in consuming code.
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 for hiding the details - this will ultimately be paired with migration guidance documentation so providing a simple and straightforward set of instructions is a high-order goal. I'll experiment with other options here though (probably pending getting some of that guidance written so we can see how it looks).
} | ||
|
||
const compatModeRuntimeOptions: Record<CompatMode, IContainerRuntimeOptions> = { |
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.
Do you think the number of features we need to disable for 1.X/enable for 2.X will continue to grow as 2.X development continues? If so, I'm wondering if it makes sense to give this object its own file if we will be continuously adding to 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 think that would represent dangerous changes, since if some featureFoo is added in say 2.3 and is incompatible with 1.4, then it's probably also incompatible with 2.0 and it would be a semver break to turn it on in a minor release.
If there are any items that get added to this config I think they'd most likely have to be features already in 2.0 but off-by-default, getting turned on in 2.3 (such that 2.0 won't blow up when it sees them).
That said, seems reasonable to split it to a separate file - I've done that in latest.
@@ -21,16 +22,16 @@ import { ScopeType } from '@fluidframework/protocol-definitions'; | |||
// @public | |||
export class AzureClient { | |||
constructor(properties: AzureClientProps); | |||
createContainer<const TContainerSchema extends ContainerSchema>(containerSchema: TContainerSchema): Promise<{ | |||
createContainer<const TContainerSchema extends ContainerSchema>(containerSchema: TContainerSchema, compatMode: CompatMode): Promise<{ |
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.
Couple questions here -
- This is a breaking change, right? Are we planning to add a changeset?
- Did we consider making
compatMode
an optional param and having it default to either"1"
or"2"
? I'm wondering if we could avoid breaking changes.
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 @ChumpChief's callout was that we want devs to explicitly opt-in to learn about implications? So our API docs better be good :)
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, I'll add a changeset.
My initial PR had a default for the param but I received feedback from the team that an explicit decision was preferred.
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 we move the logic at line 66 (copied below) to compatModeRuntimeOptions
in rootDataObject.ts
? If we can't move configProvider
configs to that file, maybe we should consider putting all the configurations in their own file like I suggested above. I think it would be best to have all of these configs in the same place
/**
* Feature gates required to support runtime compatibility when V1 and V2 clients are collaborating
*/
const azureClientV1CompatFeatureGates = {
// Disable Garbage Collection
"Fluid.GarbageCollection.RunSweep": false, // To prevent the GC op
"Fluid.GarbageCollection.DisableAutoRecovery": true, // To prevent the GC op
"Fluid.GarbageCollection.ThrowOnTombstoneLoadOverride": false, // For a consistent story of "GC is disabled"
};
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.
Good callout - I believe the plan is to leave GC off in 2.x for AzureClient in all configs so I don't think this needs to participate in the toggling, but I see the appeal of consolidating v1-compat-motivated configs together. I think for initial checkin I'll omit this but will think about it.
@@ -15,6 +15,9 @@ import { IFluidLoadable } from '@fluidframework/core-interfaces'; | |||
import { IRuntimeFactory } from '@fluidframework/container-definitions/internal'; | |||
import { ISharedObjectKind } from '@fluidframework/shared-object-base'; | |||
|
|||
// @public | |||
export type CompatMode = "1" | "2"; |
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.
Maybe a long term question, but the purpose here is to call out Supported Compat Modes for given release version? When we release 3.x I would assume compat mode options become 2 and 3?
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 personally don't think this is a sustainable approach long term so I hope we have a better solution for 3? But if not, then yes this would become "2" | "3"
in our 3.0 release to reflect that it only supports N - 1 interop.
Marking this ready for review - I had a chance to experiment with this and it worked as expected in a variety of scenarios. Main downside is that when attempting to load a "2"-mode document in a true 1.x client, the errors are a little obtuse (e.g. I hit 0x122 and "Summary metadata mismatch", Vlad's tests imply 0x162 and 0x121 would also be expected). I think this is probably best served by ensuring the documentation covers the situation well. |
// Overrides for tests | ||
files: ["src/test/*.spec.ts"], | ||
rules: { | ||
// https://mochajs.org/#arrow-functions |
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 we add a comment explaining the rationale for disabling this for tests?
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.
The URL in the comment (https://mochajs.org/#arrow-functions) describes the rationale - not sure if you saw that or if you're looking for more text directly in this file?
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.
Oh, I assumed the link was just for more general context on the rule; I didn't look. I think we should add an explicit note here as a comment (fine if we want to say "see this link for rationale for disabling in tests" or something). I'd just like for any rule deviations to have clear rationale in the docs so devs know if/when they can be changed.
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.
Added a note in latest
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.
LGTM! I think we will want to add more tests, but that can be done as a follow up. We are also still missing a changeset, but you mentioned you plan on adding that before merging
AB#7966
Based on @vladsud 's #20283 , this is a draft of API surface to toggle 1.x vs. 2.x compat mode.
Note that this feature's goal is to ensure compatible upgrade from 1.x to 2.x because the default settings don't allow for that currently. It is not a generic feature flagging API; feature owners must develop a go-to-market plan for their individual features. This API is intended to be for 1->2 only, and not for future version upgrades.
Putting up as a draft PR as a preview of the surface while I experiment with the usage.
Re: defaults and optionality, I optimized for (in order):Folks upgrading from 1.x get a compatible experience by defaultDefault values prefer 2.x except where required to satisfy bullet 1Easing eventual removal of the option by preferring optional over required so customers can omit the argument as much as possible except where required to satisfy bullet 1.EDIT: From feedback, changing to mandatory params.