Skip to content
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

Client Changes in Fluid Server Cluster Discovery Feature #9706

Merged
merged 39 commits into from
Apr 20, 2022
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
2fd9a5e
FRS-Echo-Openapis-POC
tianzhu007 Jul 29, 2021
b801558
Update openapi.json
tianzhu007 Jul 30, 2021
aa136b6
Update openapi.json
tianzhu007 Jul 30, 2021
41e35af
Upload openapi.yaml
tianzhu007 Aug 3, 2021
48b352f
Update openapi.json
tianzhu007 Aug 4, 2021
ef18375
Update openapi.json
tianzhu007 Aug 4, 2021
f5302a9
Update openapi.json
tianzhu007 Aug 4, 2021
007588a
Update openapi.json
tianzhu007 Aug 5, 2021
46e2b32
Remove openapi
tianzhu007 Nov 17, 2021
b4ae673
Merge branch 'microsoft:main' into main
tianzhu007 Dec 30, 2021
32559e6
Merge branch 'microsoft:main' into main
tianzhu007 Feb 5, 2022
14176fb
Merge branch 'microsoft:main' into main
tianzhu007 Feb 7, 2022
dcdec98
Merge branch 'microsoft:main' into main
tianzhu007 Mar 3, 2022
a03e2fa
Merge branch 'microsoft:main' into main
tianzhu007 Mar 4, 2022
16bc082
Merge branch 'microsoft:main' into main
tianzhu007 Mar 7, 2022
f9d82cb
Merge branch 'microsoft:main' into main
tianzhu007 Mar 10, 2022
cc3ffeb
Merge branch 'microsoft:main' into main
tianzhu007 Mar 30, 2022
896e174
Add the driver side change
tianzhu007 Apr 1, 2022
2560598
Merge branch 'microsoft:main' into Enable-Routing-Work-Driver
tianzhu007 Apr 1, 2022
a317f87
Add the typeValidation for driver
tianzhu007 Apr 1, 2022
3c47e1c
Merge branch 'Enable-Routing-Work-Driver' of https://github.com/tianz…
tianzhu007 Apr 1, 2022
6a0c4c0
Make enableDiscovery and noCacheManger as optional
tianzhu007 Apr 1, 2022
42aebca
Merge branch 'microsoft:main' into main
tianzhu007 Apr 5, 2022
972c260
Merge branch 'main' into Enable-Routing-Work-Driver
tianzhu007 Apr 5, 2022
9b3be88
Add the undefined check for session
tianzhu007 Apr 8, 2022
16b7f46
Add isCreateContainer flag
tianzhu007 Apr 8, 2022
626fa4e
Add the "!"
tianzhu007 Apr 8, 2022
b6f00b9
Refactor the urlUtils.ts
tianzhu007 Apr 11, 2022
0a60baf
Refactor the url methods
tianzhu007 Apr 12, 2022
ab5213f
Merge branch 'main' into Enable-Routing-Work-Driver
tianzhu007 Apr 12, 2022
824c001
Merge branch 'microsoft:main' into Enable-Routing-Work-Driver
tianzhu007 Apr 12, 2022
12467e2
Resolve url comments
tianzhu007 Apr 12, 2022
57cbf4d
Merge branch 'microsoft:main' into Enable-Routing-Work-Driver
tianzhu007 Apr 13, 2022
da55167
Change the urls, and add comments
tianzhu007 Apr 14, 2022
33d2bb1
Add the "="
tianzhu007 Apr 14, 2022
04a9eb2
Merge branch 'main' into Enable-Routing-Work-Driver
tianzhu007 Apr 18, 2022
8fbdb8d
Merge branch 'microsoft:main' into Enable-Routing-Work-Driver
tianzhu007 Apr 19, 2022
f4f696b
Merge ISession interfaces for client and server
tianzhu007 Apr 20, 2022
fbaf7bc
Remove in document metadata
tianzhu007 Apr 20, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions api-report/routerlicious-driver.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export class DocumentService implements api.IDocumentService {

// @public (undocumented)
export class DocumentStorageService extends DocumentStorageServiceProxy {
constructor(id: string, manager: GitManager, logger: ITelemetryLogger, policies?: IDocumentStorageServicePolicies, driverPolicies?: IRouterliciousDriverPolicies, blobCache?: ICache<ArrayBufferLike>, snapshotTreeCache?: ICache<ISnapshotTreeVersion>);
constructor(id: string, manager: GitManager, logger: ITelemetryLogger, policies?: IDocumentStorageServicePolicies, driverPolicies?: IRouterliciousDriverPolicies, blobCache?: ICache<ArrayBufferLike>, snapshotTreeCache?: ICache<ISnapshotTreeVersion>, noCacheGitManager?: GitManager | undefined);
// (undocumented)
getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null>;
// (undocumented)
Expand All @@ -85,11 +85,14 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
get logTailSha(): string | undefined;
// (undocumented)
manager: GitManager;
// (undocumented)
noCacheGitManager?: GitManager | undefined;
}

// @public (undocumented)
export interface IRouterliciousDriverPolicies {
aggregateBlobsSmallerThanBytes: number | undefined;
enableDiscovery?: boolean;
enablePrefetch: boolean;
enableRestLess: boolean;
enableWholeSummaryUpload: boolean;
Expand Down Expand Up @@ -143,7 +146,7 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
constructor(tokenProvider: ITokenProvider, driverPolicies?: Partial<IRouterliciousDriverPolicies>);
// (undocumented)
createContainer(createNewSummary: ISummaryTree | undefined, resolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger, clientIsSummarizer?: boolean): Promise<IDocumentService>;
createDocumentService(resolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger, clientIsSummarizer?: boolean): Promise<IDocumentService>;
createDocumentService(resolvedUrl: IResolvedUrl, logger?: ITelemetryBaseLogger, clientIsSummarizer?: boolean, isCreateContainer?: boolean): Promise<IDocumentService>;
// (undocumented)
readonly protocolName = "fluid:";
}
Expand Down
9 changes: 7 additions & 2 deletions packages/drivers/local-driver/src/localDocumentService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export class LocalDocumentService implements api.IDocumentService {
private readonly innerDocumentService?: api.IDocumentService,
) { }

public dispose() {}
public dispose() { }

/**
* Creates and returns a document storage service for local use.
Expand All @@ -43,7 +43,12 @@ export class LocalDocumentService implements api.IDocumentService {
this.documentId,
new GitManager(new TestHistorian(this.localDeltaConnectionServer.testDbFactory.testDatabase)),
new TelemetryNullLogger(),
{ minBlobSize: 2048 }); // Test blob aggregation.
{ minBlobSize: 2048 },
undefined,
undefined,
undefined,
new GitManager(new TestHistorian(this.localDeltaConnectionServer.testDbFactory.testDatabase)));
// Test blob aggregation.
tianzhu007 marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/drivers/routerlicious-driver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,4 @@
"version": "0.59.1000",
"broken": {}
}
}
}
12 changes: 12 additions & 0 deletions packages/drivers/routerlicious-driver/src/contracts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*!
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
* Licensed under the MIT License.
*/

export interface ISession {
tianzhu007 marked this conversation as resolved.
Show resolved Hide resolved
ordererUrl: string;

historianUrl: string;

isSessionAlive: boolean;
}
9 changes: 8 additions & 1 deletion packages/drivers/routerlicious-driver/src/documentService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ export class DocumentService implements api.IDocumentService {
false,
storageRestWrapper);
const gitManager = new GitManager(historian);
const noCacheHistorian = new Historian(
this.gitUrl,
true,
true,
storageRestWrapper);
const noCacheGitManager = new GitManager(noCacheHistorian);
const documentStorageServicePolicies: api.IDocumentStorageServicePolicies = {
caching: this.driverPolicies.enablePrefetch
? api.LoaderCachingPolicy.Prefetch
Expand All @@ -88,7 +94,8 @@ export class DocumentService implements api.IDocumentService {
documentStorageServicePolicies,
this.driverPolicies,
this.blobCache,
this.snapshotTreeCache);
this.snapshotTreeCache,
noCacheGitManager);
return this.documentStorageService;
}

Expand Down
56 changes: 42 additions & 14 deletions packages/drivers/routerlicious-driver/src/documentServiceFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,18 @@ import { IRouterliciousDriverPolicies } from "./policies";
import { ITokenProvider } from "./tokens";
import { RouterliciousOrdererRestWrapper } from "./restWrapper";
import { convertSummaryToCreateNewSummary } from "./createNewUtils";
import { parseFluidUrl, replaceDocumentIdInPath } from "./urlUtils";
import { parseFluidUrl, replaceDocumentIdInPath, replaceWithDiscoveredUrl } from "./urlUtils";
import { InMemoryCache } from "./cache";
import { pkgVersion as driverVersion } from "./packageVersion";
import { ISnapshotTreeVersion } from "./definitions";
import { ISession } from "./contracts";

const defaultRouterliciousDriverPolicies: IRouterliciousDriverPolicies = {
enablePrefetch: true,
maxConcurrentStorageRequests: 100,
maxConcurrentOrdererRequests: 100,
aggregateBlobsSmallerThanBytes: undefined,
enableDiscovery: false,
enableWholeSummaryUpload: false,
enableRestLess: true,
};
Expand Down Expand Up @@ -66,7 +68,7 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
ensureFluidResolvedUrl(resolvedUrl);
assert(!!createNewSummary, 0x204 /* "create empty file not supported" */);
assert(!!resolvedUrl.endpoints.ordererUrl, 0x0b2 /* "Missing orderer URL!" */);
const parsedUrl = parseFluidUrl(resolvedUrl.url);
let parsedUrl = parseFluidUrl(resolvedUrl.url);
if (!parsedUrl.pathname) {
throw new Error("Parsed url should contain tenant and doc Id!!");
}
Expand All @@ -92,15 +94,14 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
resolvedUrl.endpoints.ordererUrl,
);

// the backend responds with the actual document ID associated with the new container.

// @TODO: Remove returned "string" type when removing back-compat code
const res = await ordererRestWrapper.post<{ id: string, token?: string } | string>(
const res = await ordererRestWrapper.post<{ id: string, token?: string, session?: ISession } | string>(
`/documents/${tenantId}`,
{
summary: convertSummaryToCreateNewSummary(appSummary),
sequenceNumber: documentAttributes.sequenceNumber,
values: quorumValues,
enableDiscovery: this.driverPolicies.enableDiscovery,
generateToken: this.tokenProvider.documentPostCreateCallback !== undefined,
},
);
Expand All @@ -111,12 +112,19 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact

let documentId: string;
let token: string | undefined;
let session: ISession | undefined;

if (typeof res === "string") {
documentId = res;
} else {
documentId = res.id;
token = res.token;
session = res.session;
}

if (session && this.driverPolicies.enableDiscovery) {
replaceWithDiscoveredUrl(resolvedUrl, session, parsedUrl);
parsedUrl = parseFluidUrl(resolvedUrl.url);
}

// @TODO: Remove token from the condition, checking the documentPostCreateCallback !== undefined
Expand Down Expand Up @@ -146,6 +154,7 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
},
logger,
clientIsSummarizer,
true,
);
}

Expand All @@ -159,9 +168,37 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
resolvedUrl: IResolvedUrl,
logger?: ITelemetryBaseLogger,
clientIsSummarizer?: boolean,
isCreateContainer?: boolean,
): Promise<IDocumentService> {
ensureFluidResolvedUrl(resolvedUrl);

const parsedUrl = parseFluidUrl(resolvedUrl.url);
const [, tenantId, documentId] = parsedUrl.pathname.split("/");
if (!documentId || !tenantId) {
throw new Error(
`Couldn't parse documentId and/or tenantId. [documentId:${documentId}][tenantId:${tenantId}]`);
}
const logger2 = ChildLogger.create(logger, "RouterliciousDriver", { all: { driverVersion }});

if (!isCreateContainer && this.driverPolicies.enableDiscovery) {
const rateLimiter = new RateLimiter(this.driverPolicies.maxConcurrentOrdererRequests);
const ordererRestWrapper = await RouterliciousOrdererRestWrapper.load(
tenantId,
documentId,
this.tokenProvider,
logger2,
rateLimiter,
this.driverPolicies.enableRestLess,
resolvedUrl.endpoints.ordererUrl,
);

// the backend responds with the actual document session associated with the container.
const session: ISession = await ordererRestWrapper.get<ISession>(
`/documents/${tenantId}/session/${documentId}`,
);
replaceWithDiscoveredUrl(resolvedUrl, session, parsedUrl);
}

const fluidResolvedUrl = resolvedUrl;
const storageUrl = fluidResolvedUrl.endpoints.storageUrl;
const ordererUrl = fluidResolvedUrl.endpoints.ordererUrl;
Expand All @@ -171,15 +208,6 @@ export class RouterliciousDocumentServiceFactory implements IDocumentServiceFact
`All endpoints urls must be provided. [ordererUrl:${ordererUrl}][deltaStorageUrl:${deltaStorageUrl}]`);
}

const parsedUrl = parseFluidUrl(fluidResolvedUrl.url);
const [, tenantId, documentId] = parsedUrl.pathname.split("/");
if (!documentId || !tenantId) {
throw new Error(
`Couldn't parse documentId and/or tenantId. [documentId:${documentId}][tenantId:${tenantId}]`);
}

const logger2 = ChildLogger.create(logger, "RouterliciousDriver", { all: { driverVersion }});

return new DocumentService(
fluidResolvedUrl,
ordererUrl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
policies: IDocumentStorageServicePolicies,
driverPolicies?: IRouterliciousDriverPolicies,
blobCache?: ICache<ArrayBufferLike>,
snapshotTreeCache?: ICache<ISnapshotTreeVersion>): IDocumentStorageService {
snapshotTreeCache?: ICache<ISnapshotTreeVersion>,
noCacheGitManager?: GitManager): IDocumentStorageService {
const storageService = driverPolicies?.enableWholeSummaryUpload ?
new WholeSummaryDocumentStorageService(
id,
Expand All @@ -46,6 +47,7 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
policies,
blobCache,
snapshotTreeCache,
noCacheGitManager,
) :
new ShreddedSummaryDocumentStorageService(
id,
Expand All @@ -70,7 +72,8 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
policies: IDocumentStorageServicePolicies = {},
driverPolicies?: IRouterliciousDriverPolicies,
blobCache?: ICache<ArrayBufferLike>,
snapshotTreeCache?: ICache<ISnapshotTreeVersion>) {
snapshotTreeCache?: ICache<ISnapshotTreeVersion>,
public noCacheGitManager?: GitManager) {
super(DocumentStorageService.loadInternalDocumentStorageService(
id,
manager,
Expand All @@ -79,6 +82,7 @@ export class DocumentStorageService extends DocumentStorageServiceProxy {
driverPolicies,
blobCache,
snapshotTreeCache,
noCacheGitManager,
));
}

Expand Down
5 changes: 5 additions & 0 deletions packages/drivers/routerlicious-driver/src/policies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ export interface IRouterliciousDriverPolicies {
* Default: false
*/
enableWholeSummaryUpload: boolean;
/**
* Enable discovery for the routerlicious service
tianzhu007 marked this conversation as resolved.
Show resolved Hide resolved
* Default: false
*/
enableDiscovery?: boolean;
/**
* Enable using RestLess which avoids CORS preflight requests.
* Default: true
Expand Down
24 changes: 24 additions & 0 deletions packages/drivers/routerlicious-driver/src/urlUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
* Licensed under the MIT License.
*/

import { IFluidResolvedUrl } from "@fluidframework/driver-definitions";
import URLParse from "url-parse";
import { ISession } from "./contracts";

export const parseFluidUrl = (fluidUrl: string): URLParse => {
return new URLParse(fluidUrl, true);
Expand All @@ -17,3 +19,25 @@ export const parseFluidUrl = (fluidUrl: string): URLParse => {
*/
export const replaceDocumentIdInPath = (urlPath: string, documentId: string): string =>
urlPath.split("/").slice(0, -1).concat([documentId]).join("/");

export const createFluidUrl = (domain: string, pathname: string): string =>
tianzhu007 marked this conversation as resolved.
Show resolved Hide resolved
"fluid://".concat(domain, pathname);
tianzhu007 marked this conversation as resolved.
Show resolved Hide resolved

export const replaceWithDiscoveredUrl = (resolvedUrl: IFluidResolvedUrl,
session: ISession,
tianzhu007 marked this conversation as resolved.
Show resolved Hide resolved
parsedUrl: URLParse): void => {
if (session && session.ordererUrl.includes("https")) {
tianzhu007 marked this conversation as resolved.
Show resolved Hide resolved
resolvedUrl.url = createFluidUrl(session.ordererUrl.replace(/^https?:\/\//, ""), parsedUrl.pathname);
tianzhu007 marked this conversation as resolved.
Show resolved Hide resolved
resolvedUrl.endpoints.ordererUrl = session.ordererUrl;

const discoveredOrdererUrl = new URL(session.ordererUrl);
const deltaStorageUrl = new URL(resolvedUrl.endpoints.deltaStorageUrl);
deltaStorageUrl.host = discoveredOrdererUrl.host;
resolvedUrl.endpoints.deltaStorageUrl = deltaStorageUrl.toString();

const discoveredHistorianUrl = new URL(session.historianUrl);
const storageUrl = new URL(resolvedUrl.endpoints.storageUrl);
tianzhu007 marked this conversation as resolved.
Show resolved Hide resolved
storageUrl.host = discoveredHistorianUrl.host;
resolvedUrl.endpoints.storageUrl = storageUrl.toString();
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
protected readonly logger: ITelemetryLogger,
public readonly policies: IDocumentStorageServicePolicies = {},
private readonly blobCache: ICache<ArrayBufferLike> = new InMemoryCache(),
private readonly snapshotTreeCache: ICache<ISnapshotTreeVersion> = new InMemoryCache()) {
private readonly snapshotTreeCache: ICache<ISnapshotTreeVersion> = new InMemoryCache(),
protected readonly noCacheGitManager?: GitManager) {
this.summaryUploadManager = new WholeSummaryUploadManager(manager);
}

Expand All @@ -64,7 +65,7 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
// Fetch latest summary, cache it, and return its id.
if (this.firstVersionsCall && count === 1) {
this.firstVersionsCall = false;
const { id: _id, snapshotTree } = await this.fetchAndCacheSnapshotTree(latestSnapshotId);
const { id: _id, snapshotTree } = await this.fetchAndCacheSnapshotTree(latestSnapshotId, true);
tianzhu007 marked this conversation as resolved.
Show resolved Hide resolved
return [{
id: _id,
treeId: snapshotTree.id!,
Expand Down Expand Up @@ -170,7 +171,7 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
);
}

private async fetchAndCacheSnapshotTree(versionId: string): Promise<ISnapshotTreeVersion> {
private async fetchAndCacheSnapshotTree(versionId: string, disableCache?: boolean): Promise<ISnapshotTreeVersion> {
const cachedSnapshotTreeVersion = await this.snapshotTreeCache.get(versionId);
if (cachedSnapshotTreeVersion !== undefined) {
return { id: cachedSnapshotTreeVersion.id, snapshotTree: cachedSnapshotTreeVersion.snapshotTree };
Expand All @@ -183,7 +184,9 @@ export class WholeSummaryDocumentStorageService implements IDocumentStorageServi
treeId: versionId,
},
async (event) => {
const response = await this.manager.getSummary(versionId);
const response = disableCache !== undefined && disableCache && this.noCacheGitManager !== undefined ?
tianzhu007 marked this conversation as resolved.
Show resolved Hide resolved
await this.noCacheGitManager.getSummary(versionId) :
await this.manager.getSummary(versionId);
tianzhu007 marked this conversation as resolved.
Show resolved Hide resolved
event.end({
size: response.trees[0]?.entries.length,
});
Expand Down
18 changes: 16 additions & 2 deletions packages/test/test-drivers/src/routerliciousTestDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,26 @@ const dockerConfig = (driverPolicies?: IRouterliciousDriverPolicies) => ({
});

function getConfig(
discoveryEndpoint?: string,
fluidHost?: string,
tenantId?: string,
tenantSecret?: string,
driverPolicies?: IRouterliciousDriverPolicies) {
assert(fluidHost, "Missing Fluid host");
assert(tenantId, "Missing tenantId");
assert(tenantSecret, "Missing tenant secret");
if (discoveryEndpoint !== undefined) {
return {
serviceEndpoint: {
hostUrl: "",
ordererUrl: discoveryEndpoint,
deltaStorageUrl: "https://dummy-historian",
},
tenantId,
tenantSecret,
driverPolicies,
};
}
assert(fluidHost, "Missing Fluid host");
return {
serviceEndpoint: {
hostUrl: fluidHost,
Expand All @@ -51,10 +64,11 @@ function getConfig(
}

function getLegacyConfigFromEnv() {
const discoveryEndpoint = process.env.fluid__webpack__discoveryEndpoint;
const fluidHost = process.env.fluid__webpack__fluidHost;
const tenantSecret = process.env.fluid__webpack__tenantSecret;
const tenantId = process.env.fluid__webpack__tenantId ?? "fluid";
return getConfig(fluidHost, tenantId, tenantSecret);
return getConfig(discoveryEndpoint, fluidHost, tenantId, tenantSecret);
}

function getEndpointConfigFromEnv(r11sEndpointName: string) {
Expand Down
Loading