Skip to content

Commit

Permalink
feat: return records count in /sync/status endpoint/sdk (#2961)
Browse files Browse the repository at this point in the history
<img width="528" alt="Screenshot 2024-11-07 at 14 34 38"
src="https://github.com/user-attachments/assets/825bb1de-dd9a-4a76-865a-77a2d745054f">

## Issue ticket number and link

https://linear.app/nango/issue/NAN-1928/return-sync-object-count-from-api

## Checklist before requesting a review (skip if just adding/editing
APIs & templates)
- [ ] I added tests, otherwise the reason is: 
- [ ] I added observability, otherwise the reason is:
- [ ] I added analytics, otherwise the reason is:
  • Loading branch information
TBonnin authored Nov 12, 2024
1 parent 8ea1142 commit cbb9e81
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 12 deletions.
12 changes: 11 additions & 1 deletion docs-v2/reference/sdks/node.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,17 @@ await nango.syncStatus('<INTEGRATION-ID>', ['SYNC_NAME1', 'SYNC_NAME2'], '<CONNE
"finishedAt": "<string>",
"nextScheduledSyncAt": "<string>",
"frequency": "<string>",
"latestResult": {}
"latestResult": {
"<string>": {
"added": <number>,
"updated": <number>,
"deleted": <number>,
}
},
"recordCount": {
"<string>": <number>
...
}
}
]
}
Expand Down
3 changes: 3 additions & 0 deletions docs-v2/spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1275,6 +1275,9 @@ paths:
latestResult:
type: object
description: Additional information regarding the latest result of the sync. Contains a model name with added, updated and deleted records
recordCount:
type: object
description: Total count of records for each model synced by the sync
'400':
description: Invalid request
content:
Expand Down
1 change: 1 addition & 0 deletions packages/node-client/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ export interface SyncStatus {
status: 'RUNNING' | 'SUCCESS' | 'ERROR' | 'PAUSED' | 'STOPPED';
frequency: string;
latestResult: Record<string, StatusAction>;
recordCount: Record<string, number>;
}

export interface StatusAction {
Expand Down
10 changes: 9 additions & 1 deletion packages/server/lib/controllers/onboarding.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,15 @@ class OnboardingController {
success,
error,
response: status
} = await syncManager.getSyncStatus(environment.id, DEMO_GITHUB_CONFIG_KEY, [DEMO_SYNC_NAME], orchestrator, req.body.connectionId, true);
} = await syncManager.getSyncStatus(
environment.id,
DEMO_GITHUB_CONFIG_KEY,
[DEMO_SYNC_NAME],
orchestrator,
recordsService,
req.body.connectionId,
true
);

if (!success || !status) {
void analytics.track(AnalyticsTypes.DEMO_4_ERR, account.id, { user_id: user.id });
Expand Down
1 change: 1 addition & 0 deletions packages/server/lib/controllers/sync.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ class SyncController {
provider_config_key as string,
syncNames,
orchestrator,
recordsService,
connection_id as string,
false,
connection
Expand Down
2 changes: 2 additions & 0 deletions packages/shared/lib/clients/orchestrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { isSyncJobRunning, updateSyncJobStatus } from '../services/sync/job.serv
import { getSyncConfigRaw, getSyncConfigBySyncId } from '../services/sync/config/config.service.js';
import environmentService from '../services/environment.service.js';
import type { DBEnvironment, DBTeam } from '@nangohq/types';
import type { RecordCount } from '@nangohq/records';

export interface RecordsServiceInterface {
deleteRecordsBySyncId({
Expand All @@ -43,6 +44,7 @@ export interface RecordsServiceInterface {
model: string;
syncId: string;
}): Promise<{ totalDeletedRecords: number }>;
getRecordCountsByModel({ connectionId, environmentId }: { connectionId: number; environmentId: number }): Promise<Result<Record<string, RecordCount>>>;
}

export interface OrchestratorClientInterface {
Expand Down
11 changes: 6 additions & 5 deletions packages/shared/lib/models/Sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,16 @@ export interface Job extends TimestampsAndDeleted {

export interface ReportedSyncJobStatus {
id?: string;
type: SyncType;
type: SyncType | 'INITIAL';
name?: string;
status: SyncStatus;
latestResult?: SyncResultByModel;
latestResult?: SyncResultByModel | undefined;
jobStatus?: SyncStatus;
frequency: string;
finishedAt: Date;
frequency: string | null;
finishedAt: Date | undefined;
nextScheduledSyncAt: Date | null;
latestExecutionStatus: SyncStatus;
latestExecutionStatus: SyncStatus | undefined;
recordCount: Record<string, number>;
}

// TODO: change that to use Parsed type
Expand Down
28 changes: 23 additions & 5 deletions packages/shared/lib/services/sync/manager.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ export class SyncManagerService {
providerConfigKey: string,
syncNames: string[],
orchestrator: Orchestrator,
recordsService: RecordsServiceInterface,
connectionId?: string,
includeJobStatus = false,
optionalConnection?: Connection | null
Expand All @@ -333,7 +334,7 @@ export class SyncManagerService {
continue;
}

const reportedStatus = await this.syncStatus({ sync, environmentId, providerConfigKey, includeJobStatus, orchestrator });
const reportedStatus = await this.syncStatus({ sync, environmentId, providerConfigKey, includeJobStatus, orchestrator, recordsService });

syncsWithStatus.push(reportedStatus);
}
Expand All @@ -348,7 +349,7 @@ export class SyncManagerService {
}

for (const sync of syncs) {
const reportedStatus = await this.syncStatus({ sync, environmentId, providerConfigKey, includeJobStatus, orchestrator });
const reportedStatus = await this.syncStatus({ sync, environmentId, providerConfigKey, includeJobStatus, orchestrator, recordsService });

syncsWithStatus.push(reportedStatus);
}
Expand Down Expand Up @@ -417,13 +418,15 @@ export class SyncManagerService {
environmentId,
providerConfigKey,
includeJobStatus,
orchestrator
orchestrator,
recordsService
}: {
sync: Sync;
environmentId: number;
providerConfigKey: string;
includeJobStatus: boolean;
orchestrator: Orchestrator;
recordsService: RecordsServiceInterface;
}): Promise<ReportedSyncJobStatus> {
const latestJob = await getLatestSyncJob(sync.id);
const schedules = await orchestrator.searchSchedules([{ syncId: sync.id, environmentId }]);
Expand All @@ -432,13 +435,27 @@ export class SyncManagerService {
}
const schedule = schedules.value.get(sync.id);
let frequency = sync.frequency;
const syncConfig = await getSyncConfigByParams(environmentId, sync.name, providerConfigKey);
if (!frequency) {
const syncConfig = await getSyncConfigByParams(environmentId, sync.name, providerConfigKey);
frequency = syncConfig?.runs || null;
}
if (!schedule) {
throw new Error(`Schedule for sync ${sync.id} and environment ${environmentId} not found`);
}

const countRes = await recordsService.getRecordCountsByModel({ connectionId: sync.nango_connection_id, environmentId });
if (countRes.isErr()) {
throw new Error(`Failed to get records count for sync ${sync.id} in environment ${environmentId}: ${stringifyError(countRes.error)}`);
}
const recordCount: Record<string, number> =
syncConfig?.models.reduce(
(acc, model) => {
acc[model] = countRes.isOk() ? countRes.value[model]?.count || 0 : 0;
return acc;
},
{} as Record<string, number>
) || {};

return {
id: sync.id,
type: latestJob?.type === SyncType.INCREMENTAL ? latestJob.type : 'INITIAL',
Expand All @@ -449,8 +466,9 @@ export class SyncManagerService {
frequency,
latestResult: latestJob?.result,
latestExecutionStatus: latestJob?.status,
recordCount,
...(includeJobStatus ? { jobStatus: latestJob?.status as SyncStatus } : {})
} as ReportedSyncJobStatus;
};
}
}

Expand Down

0 comments on commit cbb9e81

Please # to comment.