Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@
const content = getAttribute(client, object, attribute)
const collaborativeDoc = makeDocCollabId(object, objectAttr)

const ydoc = getContext<YDoc>(CollaborationIds.Doc) ?? new YDoc({ guid: generateId() })
const ydoc = getContext<YDoc>(CollaborationIds.Doc) ?? new YDoc({ guid: generateId(), gc: false })
const contextProvider = getContext<Provider>(CollaborationIds.Provider)

const localProvider = createLocalProvider(ydoc, collaborativeDoc)
Expand Down Expand Up @@ -412,7 +412,7 @@
function getSavedBoard (id: string): SavedBoard {
let board = savedBoards[id]
if (board === undefined) {
const ydoc = new YDoc({ guid: id })
const ydoc = new YDoc({ guid: id, gc: false })
// We don't have a real class for boards,
// but collaborator only needs a string id
// which is produced from such an id-object
Expand Down Expand Up @@ -449,6 +449,10 @@
)
}

// it is recommended to wait for the local provider to be loaded
// https://discuss.yjs.dev/t/initial-offline-value-of-a-shared-document/465/4
await localProvider.loaded

editor = new Editor({
enableContentCheck: true,
element,
Expand Down
10 changes: 8 additions & 2 deletions server/collaborator/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export interface Config {
Secret: string

Interval: number
StorageRetryCount: number
StorageRetryInterval: number

Port: number

Expand All @@ -32,7 +34,9 @@ const envMap: { [key in keyof Config]: string } = {
Secret: 'SECRET',
Interval: 'INTERVAL',
Port: 'COLLABORATOR_PORT',
AccountsUrl: 'ACCOUNTS_URL'
AccountsUrl: 'ACCOUNTS_URL',
StorageRetryCount: 'STORAGE_RETRY_COUNT',
StorageRetryInterval: 'STORAGE_RETRY_INTERVAL'
}

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

const missingEnv = required.filter((key) => params[key] === undefined).map((key) => envMap[key])
Expand Down
8 changes: 7 additions & 1 deletion server/collaborator/src/extensions/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,15 @@ export class StorageExtension implements Extension {
this.configuration = configuration
}

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

if (document.isLoading) {
ctx.warn('document changed while is loading', { documentName, connectionId })
return
}

const updates = this.updates.get(documentName)
if (updates === undefined) {
const collaborators = new Set([connectionId])
Expand Down
6 changes: 4 additions & 2 deletions server/collaborator/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ export type Shutdown = () => Promise<void>
*/
export async function start (ctx: MeasureContext, config: Config, storageAdapter: StorageAdapter): Promise<Shutdown> {
const port = config.Port
const retryCount = config.StorageRetryCount
const retryInterval = config.StorageRetryInterval

ctx.info('Starting collaborator server', { port })
ctx.info('Starting collaborator server', { config })

const app = express()
app.use(cors())
Expand Down Expand Up @@ -95,7 +97,7 @@ export async function start (ctx: MeasureContext, config: Config, storageAdapter
}),
new StorageExtension({
ctx: extensionsCtx.newChild('storage', {}),
adapter: new PlatformStorageAdapter(storageAdapter),
adapter: new PlatformStorageAdapter(storageAdapter, { retryCount, retryInterval }),
transformer
})
]
Expand Down
48 changes: 38 additions & 10 deletions server/collaborator/src/storage/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,21 @@ import { Context } from '../context'

import { CollabStorageAdapter } from './adapter'

export interface PlatformStorageAdapterOptions {
retryCount?: number
retryInterval?: number
}
export class PlatformStorageAdapter implements CollabStorageAdapter {
constructor (private readonly storage: StorageAdapter) {}
private readonly retryCount: number
private readonly retryInterval: number

constructor (
private readonly storage: StorageAdapter,
options: PlatformStorageAdapterOptions = {}
) {
this.retryCount = options.retryCount ?? 5
this.retryInterval = options.retryInterval ?? 50
}

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

const ydoc = await ctx.with('loadCollabYdoc', {}, (ctx) => {
return withRetry(ctx, 5, () => {
return loadCollabYdoc(ctx, this.storage, context.workspaceId, documentId)
})
return withRetry(
ctx,
this.retryCount,
() => {
return loadCollabYdoc(ctx, this.storage, context.workspaceId, documentId)
},
this.retryInterval
)
})

if (ydoc !== undefined) {
Expand Down Expand Up @@ -99,9 +117,14 @@ export class PlatformStorageAdapter implements CollabStorageAdapter {
try {
ctx.info('save document ydoc content', { documentName })
await ctx.with('saveCollabYdoc', {}, (ctx) => {
return withRetry(ctx, 5, () => {
return saveCollabYdoc(ctx, this.storage, context.workspaceId, documentId, document)
})
return withRetry(
ctx,
this.retryCount,
() => {
return saveCollabYdoc(ctx, this.storage, context.workspaceId, documentId, document)
},
this.retryInterval
)
})
} catch (err: any) {
Analytics.handleError(err)
Expand Down Expand Up @@ -177,9 +200,14 @@ export class PlatformStorageAdapter implements CollabStorageAdapter {
}

const blobId = await ctx.with('saveCollabJson', {}, (ctx) => {
return withRetry(ctx, 5, () => {
return saveCollabJson(ctx, this.storage, { name: workspaceId }, documentId, markup.curr[objectAttr])
})
return withRetry(
ctx,
this.retryCount,
() => {
return saveCollabJson(ctx, this.storage, { name: workspaceId }, documentId, markup.curr[objectAttr])
},
this.retryInterval
)
})

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