Skip to content

Add SharedObjectFromKernel #24401

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

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open

Conversation

CraigMacomber
Copy link
Contributor

@CraigMacomber CraigMacomber commented Apr 18, 2025

Description

Provide makeSharedObjectKind, a new API for implementing ISharedObject which does not rely on subclassing.

Note that all the new API and abstractions here are @internal and thus could be changed or removed in the future. Additionally the new logic builds SharedObjects using the old APIs so it has no compat implications for the runtime side: this is simply providing a new option for how a SharedObject like SharedTree can be factored.

Currently the approach used to define a DDS is to subclass SharedObject.

This makes the logic used to implement the DDS not very composable. If someone wanted to use the logic from two different DDSes to implement a single one (for example to perform a migration, or to reuse the logic in multiple places like Directory almost does with map)) it is difficult.

This approach (Subclassing SharedObject) can also make targeted testing more difficult (for example requiring more mocks), since SharedObject has a significant amount of coupling to runtime types.

Further more, the existing pattern has more boilerplate than necessary as the existing pattern of implementing IChannelFactory for each SharedObject is repetitive.

Additionally, this subclassing based pattern tends to lend itself toward exporting classes, which lead to the use of both SharedObject and the factory classes in exported APIs which still impacts legacy+alpha API surfaces leaking all the base classes into the API surface.

This change introduces a new pattern, where a new purely internal interface is implemented, SharedKernelFactory, and passed to makeSharedObjectKind which handles everything else. The SharedKernelFactory exposes the impelementation of the SharedObject policy as the new SharedKernel interface. This object is separate from the app facing view, making it easier to expose minimal APIs (Like SharedTree's ITree) without leaking in APIs from SharedObject.

While currently this pattern can't support an app facing API with a property which would collide with a property of SharedObject, a limitation of all current SharedObjects, it sets up a approach which could decouple the app facing APi from SharedObject entirely in the future if desired, both making changes to SharedObject and to the app facing API surfaces easier.

In addition to just being a cleaner interface to code SharedObjects against which enable future flexibility, it also is key in enabling the migration approach taken by #23729 as it provides a common abstraction that supported SharedObjects can implement (SharedKernel) that is possible to migrate while preserving the object identity of the SharedObject which wraps it; This scenario is the main motivation for doing this now.

The approach of splitting out the core implementation logic for a DDS was inspired by SharedMap which did this with its SharedMapKernel. This didn't end up getting used to implement SharedDirectory, but the approach seems effective and could have facilatated such use.

This pattern has been successfully applied to tree and is fully hooked up to tree in this change.

This work is split out from #23729 and has some forward looking features to enable supporting SharedMap, like thisWrap which is required to implement SharedMap's "set" function which returns this.

Reviewer Guidance

The review process is outlined on this wiki page.

@Copilot Copilot AI review requested due to automatic review settings April 18, 2025 02:35
@CraigMacomber CraigMacomber requested a review from a team as a code owner April 18, 2025 02:35
@github-actions github-actions bot added area: dds Issues related to distributed data structures area: dds: tree dependencies Pull requests that update a dependency file labels Apr 18, 2025
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a new API for creating shared tree kernels without relying on subclassing by using makeSharedObjectKind. It refactors the tree factory into a functional factory (treeKernelFactory), updates tests to use an asynchronous load method, and extends SharedTreeKernel to implement the SharedKernel interface and expose a view API.

Reviewed Changes

Copilot reviewed 6 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/dds/tree/src/treeFactory.ts Refactors SharedTree implementation into a factory with makeSharedObjectKind and treeKernelFactory.
packages/dds/tree/src/test/shared-tree/sharedTree.spec.ts Updates tests to load shared trees asynchronously and adjusts assertions.
packages/dds/tree/src/shared-tree/sharedTree.ts Updates SharedTreeKernel to implement SharedKernel and expose a view API.
packages/dds/shared-object-base/src/sharedObject.ts Adds telemetryContextPrefix documentation in the constructor.
packages/dds/shared-object-base/src/index.ts Exports new symbols for the shared object kernel.
Files not reviewed (2)
  • packages/dds/shared-object-base/package.json: Language not supported
  • pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (2)

packages/dds/tree/src/treeFactory.ts:65

  • [nitpick] The variable name 'k' is ambiguous; consider renaming it to 'kernelInstance' or a similarly descriptive name for clarity.
const k = treeFromKernelArgs(args);

packages/dds/tree/src/test/shared-tree/sharedTree.spec.ts:738

  • Ensure that additional test cases are included to verify that the returned object from the asynchronous load method correctly exposes both 'kernel' and 'view', matching the expected API contract.
const tree2 = await sharedTreeFactory.load(

@github-actions github-actions bot added the base: main PRs targeted against main branch label Apr 18, 2025
@CraigMacomber CraigMacomber requested a review from a team as a code owner April 18, 2025 17:31
@github-actions github-actions bot added area: runtime Runtime related issues public api change Changes to a public API labels Apr 18, 2025
* 1. The runtime, which uses the SharedObject to summarize, load and apply ops.
* 2. The app, who uses the SharedObject to read and write data.
*
* There is some common functionality all shared objects use, provided by {@link SharedObject}.
Copy link
Contributor

@Josmithr Josmithr Apr 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I generally recommend using the link in the first reference to a type (and using ``s for subsequent references).

readonly #kernelArgs: KernelArgs;

/**
* @param id - String identifier.
Copy link
Contributor

@Josmithr Josmithr Apr 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These param docs shouldn't be necessary. Intellisense is smart enough to derive these from the docs on SharedObject.

See #24495

/**
* Utility to create a IChannelFactory classes.
* @remarks
* Prefer using {@link makeSharedObjectKind} instead of exposing the factory is not needed for legacy API compatibility.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a typo here, but it isn't immediately clear to me what the intended statement was. FYI.

@@ -186,18 +187,32 @@ function getCodecVersions(formatVersion: number): ExplicitCodecVersions {
return versions;
}

export type SharedTreeKernelView = Omit<ITreePrivate, keyof (IChannelView & IFluidLoadable)>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs?

@@ -87,6 +87,12 @@ export interface IFluidDataStoreRuntime
*/
readonly attachState: AttachState;

/**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

}

/**
* When present on a method, it indicates the methods return value should be replaced with `this` (the wrapper)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to add a usage @example

CraigMacomber and others added 2 commits May 1, 2025 09:33
Co-authored-by: Joshua Smithrud <54606601+Josmithr@users.noreply.github.com>
Copy link
Contributor

github-actions bot commented May 3, 2025

🔗 Found some broken links! 💔

Run a link check locally to find them. See
https://github.com/microsoft/FluidFramework/wiki/Checking-for-broken-links-in-the-documentation for more information.

linkcheck output


> fluid-framework-docs-site@0.0.0 ci:check-links /home/runner/work/FluidFramework/FluidFramework/docs
> start-server-and-test "npm run serve -- --no-open" 3000 check-links

1: starting server using command "npm run serve -- --no-open"
and when url "[ 'http://127.0.0.1:3000' ]" is responding with HTTP status code 200
running tests using command "npm run check-links"


> fluid-framework-docs-site@0.0.0 serve
> docusaurus serve --no-open

[SUCCESS] Serving "build" directory at: http://localhost:3000/

> fluid-framework-docs-site@0.0.0 check-links
> linkcheck http://localhost:3000 --skip-file skipped-urls.txt

Crawling...

http://localhost:3000/docs/start/tree-start
- (20:88) 'containe..' => http://localhost:3000/docs/api/container-runtime/icontainerruntimeoptions-interface (HTTP 404)


Stats:
  195689 links
    1566 destination URLs
    1797 URLs ignored
       0 warnings
       1 errors

 ELIFECYCLE  Command failed with exit code 1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: dds: tree area: dds Issues related to distributed data structures area: runtime Runtime related issues base: main PRs targeted against main branch dependencies Pull requests that update a dependency file public api change Changes to a public API
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants