Skip to content

Commit f8f3f5e

Browse files
authored
UBEF-10370 Collaborator fixes (#8889) (#8896)
Signed-off-by: Alexander Onnikov <[email protected]>
1 parent 546e9dd commit f8f3f5e

File tree

5 files changed

+63
-17
lines changed

5 files changed

+63
-17
lines changed

plugins/text-editor-resources/src/components/CollaborativeTextEditor.svelte

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@
131131
const content = getAttribute(client, object, attribute)
132132
const collaborativeDoc = makeDocCollabId(object, objectAttr)
133133
134-
const ydoc = getContext<YDoc>(CollaborationIds.Doc) ?? new YDoc({ guid: generateId() })
134+
const ydoc = getContext<YDoc>(CollaborationIds.Doc) ?? new YDoc({ guid: generateId(), gc: false })
135135
const contextProvider = getContext<Provider>(CollaborationIds.Provider)
136136
137137
const localProvider = createLocalProvider(ydoc, collaborativeDoc)
@@ -412,7 +412,7 @@
412412
function getSavedBoard (id: string): SavedBoard {
413413
let board = savedBoards[id]
414414
if (board === undefined) {
415-
const ydoc = new YDoc({ guid: id })
415+
const ydoc = new YDoc({ guid: id, gc: false })
416416
// We don't have a real class for boards,
417417
// but collaborator only needs a string id
418418
// which is produced from such an id-object
@@ -449,6 +449,10 @@
449449
)
450450
}
451451
452+
// it is recommended to wait for the local provider to be loaded
453+
// https://discuss.yjs.dev/t/initial-offline-value-of-a-shared-document/465/4
454+
await localProvider.loaded
455+
452456
editor = new Editor({
453457
enableContentCheck: true,
454458
element,

server/collaborator/src/config.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export interface Config {
2121
Secret: string
2222

2323
Interval: number
24+
StorageRetryCount: number
25+
StorageRetryInterval: number
2426

2527
Port: number
2628

@@ -32,7 +34,9 @@ const envMap: { [key in keyof Config]: string } = {
3234
Secret: 'SECRET',
3335
Interval: 'INTERVAL',
3436
Port: 'COLLABORATOR_PORT',
35-
AccountsUrl: 'ACCOUNTS_URL'
37+
AccountsUrl: 'ACCOUNTS_URL',
38+
StorageRetryCount: 'STORAGE_RETRY_COUNT',
39+
StorageRetryInterval: 'STORAGE_RETRY_INTERVAL'
3640
}
3741

3842
const required: Array<keyof Config> = ['Secret', 'ServiceID', 'Port', 'AccountsUrl']
@@ -43,7 +47,9 @@ const config: Config = (() => {
4347
ServiceID: process.env[envMap.ServiceID] ?? 'collaborator-service',
4448
Interval: parseInt(process.env[envMap.Interval] ?? '30000'),
4549
Port: parseInt(process.env[envMap.Port] ?? '3078'),
46-
AccountsUrl: process.env[envMap.AccountsUrl]
50+
AccountsUrl: process.env[envMap.AccountsUrl],
51+
StorageRetryCount: parseInt(process.env[envMap.StorageRetryCount] ?? '5'),
52+
StorageRetryInterval: parseInt(process.env[envMap.StorageRetryInterval] ?? '50')
4753
}
4854

4955
const missingEnv = required.filter((key) => params[key] === undefined).map((key) => envMap[key])

server/collaborator/src/extensions/storage.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,15 @@ export class StorageExtension implements Extension {
5555
this.configuration = configuration
5656
}
5757

58-
async onChange ({ context, documentName }: withContext<onChangePayload>): Promise<any> {
58+
async onChange ({ context, document, documentName }: withContext<onChangePayload>): Promise<any> {
59+
const { ctx } = this.configuration
5960
const { connectionId } = context
6061

62+
if (document.isLoading) {
63+
ctx.warn('document changed while is loading', { documentName, connectionId })
64+
return
65+
}
66+
6167
const updates = this.updates.get(documentName)
6268
if (updates === undefined) {
6369
const collaborators = new Set([connectionId])

server/collaborator/src/server.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@ export type Shutdown = () => Promise<void>
4343
*/
4444
export async function start (ctx: MeasureContext, config: Config, storageAdapter: StorageAdapter): Promise<Shutdown> {
4545
const port = config.Port
46+
const retryCount = config.StorageRetryCount
47+
const retryInterval = config.StorageRetryInterval
4648

47-
ctx.info('Starting collaborator server', { port })
49+
ctx.info('Starting collaborator server', { config })
4850

4951
const app = express()
5052
app.use(cors())
@@ -95,7 +97,7 @@ export async function start (ctx: MeasureContext, config: Config, storageAdapter
9597
}),
9698
new StorageExtension({
9799
ctx: extensionsCtx.newChild('storage', {}),
98-
adapter: new PlatformStorageAdapter(storageAdapter),
100+
adapter: new PlatformStorageAdapter(storageAdapter, { retryCount, retryInterval }),
99101
transformer
100102
})
101103
]

server/collaborator/src/storage/platform.ts

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,21 @@ import { Context } from '../context'
2727

2828
import { CollabStorageAdapter } from './adapter'
2929

30+
export interface PlatformStorageAdapterOptions {
31+
retryCount?: number
32+
retryInterval?: number
33+
}
3034
export class PlatformStorageAdapter implements CollabStorageAdapter {
31-
constructor (private readonly storage: StorageAdapter) {}
35+
private readonly retryCount: number
36+
private readonly retryInterval: number
37+
38+
constructor (
39+
private readonly storage: StorageAdapter,
40+
options: PlatformStorageAdapterOptions = {}
41+
) {
42+
this.retryCount = options.retryCount ?? 5
43+
this.retryInterval = options.retryInterval ?? 50
44+
}
3245

3346
async loadDocument (ctx: MeasureContext, documentName: string, context: Context): Promise<YDoc | undefined> {
3447
const { content, workspaceId } = context
@@ -39,9 +52,14 @@ export class PlatformStorageAdapter implements CollabStorageAdapter {
3952
ctx.info('load document content', { documentName })
4053

4154
const ydoc = await ctx.with('loadCollabYdoc', {}, (ctx) => {
42-
return withRetry(ctx, 5, () => {
43-
return loadCollabYdoc(ctx, this.storage, context.workspaceId, documentId)
44-
})
55+
return withRetry(
56+
ctx,
57+
this.retryCount,
58+
() => {
59+
return loadCollabYdoc(ctx, this.storage, context.workspaceId, documentId)
60+
},
61+
this.retryInterval
62+
)
4563
})
4664

4765
if (ydoc !== undefined) {
@@ -99,9 +117,14 @@ export class PlatformStorageAdapter implements CollabStorageAdapter {
99117
try {
100118
ctx.info('save document ydoc content', { documentName })
101119
await ctx.with('saveCollabYdoc', {}, (ctx) => {
102-
return withRetry(ctx, 5, () => {
103-
return saveCollabYdoc(ctx, this.storage, context.workspaceId, documentId, document)
104-
})
120+
return withRetry(
121+
ctx,
122+
this.retryCount,
123+
() => {
124+
return saveCollabYdoc(ctx, this.storage, context.workspaceId, documentId, document)
125+
},
126+
this.retryInterval
127+
)
105128
})
106129
} catch (err: any) {
107130
Analytics.handleError(err)
@@ -177,9 +200,14 @@ export class PlatformStorageAdapter implements CollabStorageAdapter {
177200
}
178201

179202
const blobId = await ctx.with('saveCollabJson', {}, (ctx) => {
180-
return withRetry(ctx, 5, () => {
181-
return saveCollabJson(ctx, this.storage, { name: workspaceId }, documentId, markup.curr[objectAttr])
182-
})
203+
return withRetry(
204+
ctx,
205+
this.retryCount,
206+
() => {
207+
return saveCollabJson(ctx, this.storage, { name: workspaceId }, documentId, markup.curr[objectAttr])
208+
},
209+
this.retryInterval
210+
)
183211
})
184212

185213
await ctx.with('update', {}, () => client.diffUpdate(current, { [objectAttr]: blobId }))

0 commit comments

Comments
 (0)