diff --git a/services/github/pod-github/src/platform.ts b/services/github/pod-github/src/platform.ts index db46bcc20c..36892bb5d3 100644 --- a/services/github/pod-github/src/platform.ts +++ b/services/github/pod-github/src/platform.ts @@ -90,7 +90,7 @@ export class PlatformWorker { readonly ctx: MeasureContext, readonly app: App, readonly brandingMap: BrandingMap, - readonly periodicSyncInterval = 10 * 60 * 1000 // 10 minutes + readonly periodicSyncInterval = 24 * 60 * 60 * 1000 // 24 hours ) { registerLoaders() } @@ -732,7 +732,7 @@ export class PlatformWorker { } } - async checkRefreshToken (ctx: MeasureContext, auth: GithubUserRecord, force: boolean = false): Promise { + async checkRefreshToken (ctx: MeasureContext, auth: GithubUserRecord, force: boolean = false): Promise { if (auth.refreshToken != null && auth.expiresIn != null && auth.expiresIn < Date.now() / 1000) { const uri = 'https://github.com/login/oauth/access_token?' + @@ -754,6 +754,7 @@ export class PlatformWorker { if (resultJson.error !== undefined) { // We need to clear github integration info. await this.revokeUserAuth(ctx, auth) + return false } else { // Update okit const nowTime = Date.now() / 1000 @@ -774,8 +775,10 @@ export class PlatformWorker { auth.scope = dta.scope await this.userManager.updateUser(dta) + return true } } + return true } async getAccount (login: string): Promise { diff --git a/services/github/pod-github/src/sync/comments.ts b/services/github/pod-github/src/sync/comments.ts index baf8ebf439..c5dfe2f39d 100644 --- a/services/github/pod-github/src/sync/comments.ts +++ b/services/github/pod-github/src/sync/comments.ts @@ -80,8 +80,14 @@ export class CommentSyncManager implements DocSyncManager { await this.eventSync.get(event.issue.url) const promise = this.processEvent(ctx, event, derivedClient, integration) this.eventSync.set(event.issue.url, promise) - await promise - this.eventSync.delete(event.issue.url) + try { + await promise + this.eventSync.delete(event.issue.url) + } catch (err: any) { + ctx.error('Error processing event', { error: err }) + } finally { + this.eventSync.delete(event.issue.url) + } } async handleDelete ( diff --git a/services/github/pod-github/src/sync/issueBase.ts b/services/github/pod-github/src/sync/issueBase.ts index 0ef7e42bcb..1cd2872dd0 100644 --- a/services/github/pod-github/src/sync/issueBase.ts +++ b/services/github/pod-github/src/sync/issueBase.ts @@ -22,7 +22,8 @@ import core, { Ref, Space, TxOperations, - makeDocCollabId + makeDocCollabId, + withContext } from '@hcengineering/core' import github, { DocSyncInfo, GithubIntegrationRepository, GithubIssue, GithubProject } from '@hcengineering/github' import { IntlString } from '@hcengineering/platform' @@ -112,6 +113,7 @@ export abstract class IssueSyncManagerBase { return socialIds.map((it) => it.attachedTo) } + @withContext('issues-handleUpdate') async handleUpdate ( ctx: MeasureContext, external: IssueExternalData, @@ -135,12 +137,16 @@ export abstract class IssueSyncManagerBase { syncData = syncData ?? - (await this.client.findOne(github.class.DocSyncInfo, { space: prj._id, url: (external.url ?? '').toLowerCase() })) + (await ctx.with('findDocInfo', {}, (ctx) => + this.client.findOne(github.class.DocSyncInfo, { space: prj._id, url: (external.url ?? '').toLowerCase() }) + )) if (syncData !== undefined) { - const doc: Issue | undefined = await this.client.findOne(syncData.objectClass, { - _id: syncData._id as unknown as Ref - }) + const doc: Issue | undefined = await ctx.with('find pull request', {}, (ctx) => + this.client.findOne(syncData.objectClass, { + _id: syncData._id as unknown as Ref + }) + ) // Use now as modified date for events. const lastModified = new Date().getTime() @@ -153,6 +159,7 @@ export abstract class IssueSyncManagerBase { ) { try { const collabId = makeDocCollabId(doc, 'description') + await this.collaborator.updateMarkup(collabId, update.description) } catch (err: any) { Analytics.handleError(err) @@ -184,35 +191,39 @@ export abstract class IssueSyncManagerBase { await updateTodos.commit() } - await derivedClient.diffUpdate( - syncData, - { - external, - externalVersion: githubExternalSyncVersion, - current: { ...syncData.current, ...update }, - needSync: needSync ? '' : githubSyncVersion, // No need to sync after operation. - derivedVersion: '', // Check derived changes - lastModified, - lastGithubUser: account, - ...extraSyncUpdate - }, - lastModified + await ctx.with('diffUpdate syncData', {}, (ctx) => + derivedClient.diffUpdate( + syncData, + { + external, + externalVersion: githubExternalSyncVersion, + current: { ...syncData.current, ...update }, + needSync: needSync ? '' : githubSyncVersion, // No need to sync after operation. + derivedVersion: '', // Check derived changes + lastModified, + lastGithubUser: account, + ...extraSyncUpdate + }, + lastModified + ) ) - await this.client.diffUpdate(doc, issueData, lastModified, account) + await ctx.with('diffUpdate-issue', {}, (ctx) => this.client.diffUpdate(doc, issueData, lastModified, account)) this.provider.sync() } else if (doc === undefined) { - await derivedClient.diffUpdate( - syncData, - { - external, - externalVersion: githubExternalSyncVersion, - needSync: '', - derivedVersion: '', // Check derived changes - lastModified, - lastGithubUser: account, - ...extraSyncUpdate - }, - lastModified + await ctx.with('diffUpdate-syncData', {}, (ctx) => + derivedClient.diffUpdate( + syncData, + { + external, + externalVersion: githubExternalSyncVersion, + needSync: '', + derivedVersion: '', // Check derived changes + lastModified, + lastGithubUser: account, + ...extraSyncUpdate + }, + lastModified + ) ) } } @@ -267,6 +278,7 @@ export abstract class IssueSyncManagerBase { info: DocSyncInfo ): Promise + @withContext('issues-handleDiffUpdate') async handleDiffUpdate ( ctx: MeasureContext, container: ContainerFocus, @@ -282,7 +294,7 @@ export abstract class IssueSyncManagerBase { await ctx.with( 'create mixin issue: GithubIssue', {}, - async () => { + async (ctx) => { await this.client.createMixin( existing._id as Ref, existing._class, diff --git a/services/github/pod-github/src/sync/issues.ts b/services/github/pod-github/src/sync/issues.ts index 19410d4249..84d9ac68db 100644 --- a/services/github/pod-github/src/sync/issues.ts +++ b/services/github/pod-github/src/sync/issues.ts @@ -111,11 +111,16 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan const urlId = issueEvent.issue.url await syncRunner.exec(urlId, async () => { - await this.processEvent(ctx, issueEvent, derivedClient, repository, integration, project) + try { + await this.processEvent(ctx, issueEvent, derivedClient, repository, integration, project) + } catch (err: any) { + ctx.error('Error processing event', { error: err }) + } }) } } + @withContext('issues-processEvent') private async processEvent ( ctx: MeasureContext, event: IssuesEvent, @@ -129,8 +134,9 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan let externalData: IssueExternalData | undefined if (event.action !== 'deleted') { try { - const response: any = await integration.octokit?.graphql( - `query listIssue($name: String!, $owner: String!, $issue: Int!) { + const response: any = await ctx.with('graphql', {}, (ctx) => + integration.octokit?.graphql( + `query listIssue($name: String!, $owner: String!, $issue: Int!) { repository(name: $name, owner: $owner) { issue(number: $issue) { ${issueDetails(true)} @@ -138,11 +144,12 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan } } `, - { - name: repo.name, - owner: repo.owner?.login, - issue: event.issue.number - } + { + name: repo.name, + owner: repo.owner?.login, + issue: event.issue.number + } + ) ) externalData = response.repository.issue } catch (err: any) { @@ -351,7 +358,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan const description = await ctx.with( 'query collaborative description', {}, - async () => { + async (ctx) => { const collabId = makeDocCollabId(existing, 'description') return await this.collaborator.getMarkup(collabId, (existing as Issue).description) }, @@ -367,7 +374,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan const createdIssueData = await ctx.with( 'create github issue', {}, - async () => { + async (ctx) => { this.createPromise = this.createGithubIssue( ctx, container, @@ -501,10 +508,11 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan await ctx.with( 'create platform issue', {}, - async () => { + async (ctx) => { const st = (await guessStatus(issueExternal, statuses))._id as Ref await this.createNewIssue( + ctx, info, accountGH, { @@ -555,7 +563,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan const updateResult = await ctx.with( 'diff update', {}, - async () => + async (ctx) => await this.handleDiffUpdate( ctx, container, @@ -655,7 +663,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan await ctx.with( '==> updateIssue', {}, - async () => { + async (ctx) => { ctx.info('update fields', { url: issueExternal.url, ...issueUpdate, @@ -696,7 +704,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan await ctx.with( '==> updateIssue', {}, - async () => { + async (ctx) => { ctx.info('update fields', { ...issueUpdate, workspace: this.provider.getWorkspaceId() }) if (isGHWriteAllowed()) { const hasOtherChanges = Object.keys(issueUpdate).length > 0 @@ -807,7 +815,9 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan } } + @withContext('issues-createNewIssue') private async createNewIssue ( + ctx: MeasureContext, info: DocSyncInfo, account: PersonId, issueData: GithubIssueData & { status: Issue['status'] }, @@ -930,7 +940,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan const response: any = await ctx.with( 'graphql.listIssue', {}, - () => + (ctx) => integration.octokit.graphql( `query listIssues { nodes(ids: [${idsp}] ) { diff --git a/services/github/pod-github/src/sync/pullrequests.ts b/services/github/pod-github/src/sync/pullrequests.ts index 314a6e9750..a179b18fc5 100644 --- a/services/github/pod-github/src/sync/pullrequests.ts +++ b/services/github/pod-github/src/sync/pullrequests.ts @@ -122,11 +122,16 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS const url = event.pull_request.issue_url await syncRunner.exec(url, async () => { - await this.processEvent(ctx, event, derivedClient, repository, integration, project) + try { + await this.processEvent(ctx, event, derivedClient, repository, integration, project) + } catch (err: any) { + ctx.error('Error processing event', { error: err }) + } }) } } + @withContext('pullrequests-processEvent') private async processEvent ( ctx: MeasureContext, event: PullRequestEvent, @@ -139,8 +144,9 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS let externalData: PullRequestExternalData try { - const response: any = await integration.octokit?.graphql( - `query listIssue($name: String!, $owner: String!, $issue: Int!) { + const response: any = await ctx.with('graphql', {}, (ctx) => + integration.octokit?.graphql( + `query listIssue($name: String!, $owner: String!, $issue: Int!) { repository(name: $name, owner: $owner) { pullRequest(number: $issue) { ${pullRequestDetails} @@ -148,11 +154,12 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS } } `, - { - name: repo.name, - owner: repo.owner?.login, - issue: event.pull_request.number - } + { + name: repo.name, + owner: repo.owner?.login, + issue: event.pull_request.number + } + ) ) externalData = response.repository.pullRequest } catch (err: any) { @@ -496,7 +503,7 @@ export class PullRequestSyncManager extends IssueSyncManagerBase implements DocS } // To sync reviews/review threads in case they are created before us. - await syncChilds(info, this.client, derivedClient) + await syncChilds(ctx, info, this.client, derivedClient) return { needSync: '', diff --git a/services/github/pod-github/src/sync/reviewComments.ts b/services/github/pod-github/src/sync/reviewComments.ts index 5cf98b349b..5685daf810 100644 --- a/services/github/pod-github/src/sync/reviewComments.ts +++ b/services/github/pod-github/src/sync/reviewComments.ts @@ -88,8 +88,13 @@ export class ReviewCommentSyncManager implements DocSyncManager { await this.eventSync.get(event.comment.html_url) const promise = this.processEvent(ctx, event, derivedClient, repository, integration) this.eventSync.set(event.comment.html_url, promise) - await promise - this.eventSync.delete(event.comment.html_url) + try { + await promise + } catch (err: any) { + ctx.error('Error processing event', { error: err }) + } finally { + this.eventSync.delete(event.comment.html_url) + } } async handleDelete ( @@ -364,7 +369,7 @@ export class ReviewCommentSyncManager implements DocSyncManager { } if (existing === undefined) { try { - await this.createReviewComment(info, messageData, parent, reviewComment, account) + await this.createReviewComment(ctx, info, messageData, parent, reviewComment, account) return { needSync: githubSyncVersion, current: messageData } } catch (err: any) { ctx.error('Error', { err }) @@ -387,6 +392,7 @@ export class ReviewCommentSyncManager implements DocSyncManager { return { current: messageData, needSync: githubSyncVersion } } + @withContext('handleDiffUpdate-comment') private async handleDiffUpdate ( ctx: MeasureContext, existing: Doc, @@ -458,7 +464,9 @@ export class ReviewCommentSyncManager implements DocSyncManager { } } + @withContext('review-comments-createReviewComment') private async createReviewComment ( + ctx: MeasureContext, info: DocSyncInfo, messageData: ReviewCommentData, parent: DocSyncInfo, @@ -482,6 +490,7 @@ export class ReviewCommentSyncManager implements DocSyncManager { ) } + @withContext('review-comments-create') async createGithubReviewComment ( ctx: MeasureContext, container: ContainerFocus, diff --git a/services/github/pod-github/src/sync/reviewThreads.ts b/services/github/pod-github/src/sync/reviewThreads.ts index b146b0dcb3..762392f159 100644 --- a/services/github/pod-github/src/sync/reviewThreads.ts +++ b/services/github/pod-github/src/sync/reviewThreads.ts @@ -108,8 +108,13 @@ export class ReviewThreadSyncManager implements DocSyncManager { await this.eventSync.get(event.thread.node_id) const promise = this.processEvent(ctx, event, derivedClient, repository, integration) this.eventSync.set(event.thread.node_id, promise) - await promise - this.eventSync.delete(event.thread.node_id) + try { + await promise + } catch (err: any) { + ctx.error('Error processing event', { error: err }) + } finally { + this.eventSync.delete(event.thread.node_id) + } } async handleDelete ( @@ -311,7 +316,7 @@ export class ReviewThreadSyncManager implements DocSyncManager { await this.createReviewThread(info, messageData, parent, review, account) // We need trigger comments, if their sync data created before - await syncChilds(info, this.client, derivedClient) + await syncChilds(ctx, info, this.client, derivedClient) return { needSync: githubSyncVersion, current: messageData } } catch (err: any) { ctx.error('Error', { err }) diff --git a/services/github/pod-github/src/sync/reviews.ts b/services/github/pod-github/src/sync/reviews.ts index cee3e178ee..5361480787 100644 --- a/services/github/pod-github/src/sync/reviews.ts +++ b/services/github/pod-github/src/sync/reviews.ts @@ -86,8 +86,13 @@ export class ReviewSyncManager implements DocSyncManager { await this.eventSync.get(event.review.html_url) const promise = this.processEvent(ctx, event, derivedClient, repository, integration) this.eventSync.set(event.review.html_url, promise) - await promise - this.eventSync.delete(event.review.html_url) + try { + await promise + } catch (err: any) { + ctx.error('Error processing event', { error: err }) + } finally { + this.eventSync.delete(event.review.html_url) + } } async handleDelete ( @@ -318,9 +323,9 @@ export class ReviewSyncManager implements DocSyncManager { } if (existing === undefined) { try { - await this.createReview(info, messageData, parent, review, account) + await this.createReview(ctx, info, messageData, parent, review, account) - await syncChilds(info, this.client, derivedClient) + await syncChilds(ctx, info, this.client, derivedClient) return { needSync: githubSyncVersion, current: messageData } } catch (err: any) { ctx.error('Error', { err }) @@ -328,12 +333,14 @@ export class ReviewSyncManager implements DocSyncManager { return { needSync: githubSyncVersion, error: errorToObj(err) } } } else { - await this.handleDiffUpdate(existing, info, messageData, container, parent, review, account) + await this.handleDiffUpdate(ctx, existing, info, messageData, container, parent, review, account) } return { current: messageData, needSync: githubSyncVersion } } + @withContext('reviews-handleDiffUpdate') private async handleDiffUpdate ( + ctx: MeasureContext, existing: Doc, info: DocSyncInfo, reviewData: ReviewData, @@ -379,7 +386,9 @@ export class ReviewSyncManager implements DocSyncManager { } } + @withContext('reviews-createReview') private async createReview ( + ctx: MeasureContext, info: DocSyncInfo, messageData: ReviewData, parent: DocSyncInfo, @@ -403,6 +412,7 @@ export class ReviewSyncManager implements DocSyncManager { ) } + @withContext('reviews-createGithubReview') async createGithubReview ( ctx: MeasureContext, container: ContainerFocus, diff --git a/services/github/pod-github/src/sync/utils.ts b/services/github/pod-github/src/sync/utils.ts index f22edc33e2..342224b53f 100644 --- a/services/github/pod-github/src/sync/utils.ts +++ b/services/github/pod-github/src/sync/utils.ts @@ -196,9 +196,11 @@ export class SyncRunner { id, promise.then(() => {}) ) - const result = await promise - this.eventSync.delete(id) - return result + try { + return await promise + } finally { + this.eventSync.delete(id) + } } } @@ -328,13 +330,20 @@ export function compareMarkdown (a: string, b: string): boolean { return na === nb } -export async function syncChilds (info: DocSyncInfo, client: TxOperations, derivedClient: TxOperations): Promise { - const childInfos = await client.findAll(github.class.DocSyncInfo, { parent: info.url.toLowerCase() }) +export async function syncChilds ( + ctx: MeasureContext, + info: DocSyncInfo, + client: TxOperations, + derivedClient: TxOperations +): Promise { + const childInfos = await ctx.with('syncChilds-find', {}, () => + client.findAll(github.class.DocSyncInfo, { parent: info.url.toLowerCase() }) + ) if (childInfos.length > 0) { const ops = derivedClient.apply() for (const child of childInfos) { await ops?.update(child, { needSync: '' }) } - await ops.commit() + await ctx.with('sync-child-trigger', {}, () => ops.commit()) } } diff --git a/services/github/pod-github/src/types.ts b/services/github/pod-github/src/types.ts index 8957035d14..80e9f4ceed 100644 --- a/services/github/pod-github/src/types.ts +++ b/services/github/pod-github/src/types.ts @@ -224,4 +224,6 @@ export interface GithubUserRecord { scope?: string error?: string | null accounts: Record + + octokit?: Octokit } diff --git a/services/github/pod-github/src/users.ts b/services/github/pod-github/src/users.ts index 4a6a562db8..3771cd52be 100644 --- a/services/github/pod-github/src/users.ts +++ b/services/github/pod-github/src/users.ts @@ -45,6 +45,15 @@ export class UserManager { } failedRefs = new Set() + + cacheRecord (workspace: WorkspaceUuid, ref: PersonId, record: GithubUserRecord): void { + if (this.refUserCache.size > 1000) { + this.refUserCache.clear() + } + const key = `${workspace}.${ref}` + this.refUserCache.set(key, record) + } + async getAccountByRef ( ctx: MeasureContext, workspace: WorkspaceUuid, diff --git a/services/github/pod-github/src/worker.ts b/services/github/pod-github/src/worker.ts index 9780b2a976..d1ff76ebfb 100644 --- a/services/github/pod-github/src/worker.ts +++ b/services/github/pod-github/src/worker.ts @@ -560,13 +560,19 @@ export class GithubWorker implements IntegrationManager { async syncUserData (ctx: MeasureContext): Promise { // Let's sync information about users and send some details - const accounts = await this._client.findAll(contact.class.SocialIdentity, { - type: SocialIdType.GITHUB - }) - const userAuths = await this._client.findAll(github.class.GithubAuthentication, {}) - const persons = await this._client.findAll(contact.class.Person, { - _id: { $in: accounts.map((it) => it.attachedTo) } - }) + const accounts = await ctx.with('find-social-id', {}, () => + this._client.findAll(contact.class.SocialIdentity, { + type: SocialIdType.GITHUB + }) + ) + const userAuths = await ctx.with('find-github-auths', {}, () => + this._client.findAll(github.class.GithubAuthentication, {}) + ) + const persons = await ctx.with('find-persons', {}, () => + this._client.findAll(contact.class.Person, { + _id: { $in: accounts.map((it) => it.attachedTo) } + }) + ) for (const account of accounts) { const userAuth = userAuths.find((it) => it.login === account.value) const person = persons.find((it) => account?.attachedTo) @@ -611,13 +617,18 @@ export class GithubWorker implements IntegrationManager { async getOctokit (ctx: MeasureContext, account: PersonId): Promise { let record = await this.platform.getAccountByRef(this.workspace.uuid, account) - const accountRef = await this._client.findOne(contact.class.SocialIdentity, { _id: account as any }) if (record === undefined) { + const accountRef = await ctx.with('find-social-id', {}, () => + this._client.findOne(contact.class.SocialIdentity, { _id: account as any }) + ) if (accountRef !== undefined) { - const accounts = await this._client.findAll(contact.class.SocialIdentity, { attachedTo: accountRef.attachedTo }) + const accounts = await ctx.with('find-accounts', {}, () => + this._client.findAll(contact.class.SocialIdentity, { attachedTo: accountRef.attachedTo }) + ) for (const aa of accounts) { record = await this.platform.getAccountByRef(this.workspace.uuid, aa._id) if (record !== undefined) { + this.platform.userManager.cacheRecord(this.workspace.uuid, account, record) break } } @@ -625,33 +636,55 @@ export class GithubWorker implements IntegrationManager { } // Check and refresh token if required. if (record !== undefined) { - this.ctx.info('get octokit', { account, recordId: record._id, workspace: this.workspace.uuid }) - await this.platform.checkRefreshToken(ctx, record) - return new Octokit({ - auth: record.token, - client_id: config.ClientID, - client_secret: config.ClientSecret - }) + ctx.info('get octokit', { account, recordId: record._id, workspace: this.workspace.uuid }) + if (!(await this.platform.checkRefreshToken(ctx, record))) { + record.octokit = undefined + } + if (record.octokit !== undefined) { + return record.octokit + } + + record.octokit = ctx.withSync( + 'create-octokit', + {}, + () => + new Octokit({ + auth: record.token, + client_id: config.ClientID, + client_secret: config.ClientSecret + }) + ) + return record.octokit } // We need to inform user, he need to authorize this account with github. // TODO: Inform user it need authenticsion if (!this.authRequestSend.has(account)) { this.authRequestSend.add(account) - const socialId = await this._client.findOne(contact.class.SocialIdentity, { _id: account as any }) + const socialId = await ctx.with('find-social-id', {}, () => + this._client.findOne(contact.class.SocialIdentity, { _id: account as any }) + ) if (socialId !== undefined) { - const personSpace = await this.liveQuery.findOne(contact.class.PersonSpace, { person: socialId.attachedTo }) - const person = await this._client.findOne(contact.mixin.Employee, { _id: socialId.attachedTo as Ref }) + const personSpace = await ctx.with('find-person-space', {}, () => + this.liveQuery.findOne(contact.class.PersonSpace, { person: socialId.attachedTo }) + ) + const person = await ctx.with('find-person', {}, () => + this._client.findOne(contact.mixin.Employee, { _id: socialId.attachedTo as Ref }) + ) if (personSpace !== undefined && person !== undefined) { // We need to remove if user has authentication in workspace but doesn't have a record. - const allSocialId = await this._client.findAll(contact.class.SocialIdentity, { - attachedTo: personSpace.person - }) + const allSocialId = await ctx.with('find-all-social-ids', {}, () => + this._client.findAll(contact.class.SocialIdentity, { + attachedTo: personSpace.person + }) + ) - const authentications = await this.liveQuery.findAll(github.class.GithubAuthentication, { - createdBy: { $in: allSocialId.map((it) => it._id) } - }) + const authentications = await ctx.with('find-authentications', {}, () => + this.liveQuery.findAll(github.class.GithubAuthentication, { + createdBy: { $in: allSocialId.map((it) => it._id) } + }) + ) for (const auth of authentications) { await this._client.remove(auth) } @@ -1026,7 +1059,7 @@ export class GithubWorker implements IntegrationManager { continue } - this.ctx.info('External Syncing', { + ctx.info('External Syncing', { name: repo.name, prj: prj.name, field, @@ -1042,7 +1075,7 @@ export class GithubWorker implements IntegrationManager { await mapper?.externalSync(ctx, integration, derivedClient, field, _docs, repo, prj) } catch (err: any) { Analytics.handleError(err) - this.ctx.error('failed to perform external sync', err) + ctx.error('failed to perform external sync', err) } } } @@ -1578,10 +1611,10 @@ export class GithubWorker implements IntegrationManager { if (this.closing) { break } - await this.ctx.with( + await ctx.with( 'external sync', {}, - async () => { + async (ctx) => { const enabled = integration.enabled && integration.octokit !== undefined const upd: DocumentUpdate = {} @@ -1622,10 +1655,8 @@ export class GithubWorker implements IntegrationManager { if (this.closing) { break } - const withError = await derivedClient.findAll( - github.class.DocSyncInfo, - { error: { $ne: null }, url: null }, - { limit: 50 } + const withError = await ctx.with('find-docSyncInfo', {}, () => + derivedClient.findAll(github.class.DocSyncInfo, { error: { $ne: null }, url: null }, { limit: 50 }) ) if (withError.length === 0) { @@ -1642,10 +1673,8 @@ export class GithubWorker implements IntegrationManager { if (this.closing) { break } - const withError = await derivedClient.findAll( - github.class.DocSyncInfo, - { error: { $ne: null } }, - { limit: 50 } + const withError = await ctx.with('find-docSyncInfo-errors', {}, () => + derivedClient.findAll(github.class.DocSyncInfo, { error: { $ne: null } }, { limit: 50 }) ) if (withError.length === 0) { @@ -1666,17 +1695,17 @@ export class GithubWorker implements IntegrationManager { await ops.update(d, { error: null, needSync: skipError ? githubSyncVersion : '' }) } - await ops.commit() + await ctx.with('commit-errors-docsync-info', {}, () => ops.commit()) } for (const { _class, mapper } of this.mappers) { if (this.closing) { break } - await this.ctx.with( - 'external sync', - { _class: _class.join(', ') }, - async () => { + await ctx.with( + 'mapper external sync', + {}, + async (ctx) => { await mapper.externalFullSync(ctx, integration, derivedClient, _projects, _repositories) }, { installation: integration.installationName, workspace: this.workspace.uuid }, @@ -1810,11 +1839,14 @@ export async function syncUser ( client: TxOperations, account: PersonId ): Promise { - const okit = new Octokit({ - auth: record.token, - client_id: config.ClientID, - client_secret: config.ClientSecret - }) + const okit = + record.octokit ?? + new Octokit({ + auth: record.token, + client_id: config.ClientID, + client_secret: config.ClientSecret + }) + record.octokit = okit const details = await fetchViewerDetails(okit)