From 9876137d4dcaf8f13138eeabc5feb3f3eeb1cacc Mon Sep 17 00:00:00 2001 From: massimoalbarello Date: Fri, 2 Oct 2026 18:26:11 +0100 Subject: [PATCH 1/5] refactor: centralize sync polling in cron --- README.md | 6 +- .../backend/src/services/dashboard/service.ts | 2 - .../src/routes/_workspace/syncs.$id.tsx | 15 -- .../src/routes/_workspace/syncs.index.tsx | 6 +- packages/sync/src/db/client.ts | 13 +- packages/sync/src/db/schema.sql | 2 +- packages/sync/src/execution/worker.ts | 13 +- packages/sync/src/http/controller.ts | 1 - packages/sync/src/models/definition.ts | 2 +- packages/sync/src/models/sync.ts | 10 +- .../src/repositories/acquisition/contract.ts | 1 + .../src/repositories/acquisition/lease.ts | 12 +- .../src/repositories/acquisition/sqlite.ts | 11 +- .../sync/src/repositories/assets/sqlite.ts | 4 +- .../sync/src/repositories/catalog/sqlite.ts | 27 ++-- .../sync/src/repositories/delivery/sqlite.ts | 4 +- packages/sync/src/repositories/rows.ts | 3 +- packages/sync/src/services/acquisition.ts | 3 + packages/sync/src/services/management.ts | 5 +- packages/sync/test/acquisition-retry.test.ts | 14 +- packages/sync/test/connector-failure.test.ts | 4 +- packages/sync/test/package-consumer.ts | 5 +- packages/sync/test/persistence.test.ts | 2 +- packages/sync/test/polling-migration.test.ts | 110 +++++++++++++++ packages/sync/test/run-due.test.ts | 132 ++++++++++++++++-- packages/sync/test/shared-backoff.test.ts | 2 +- packages/sync/test/source-http-error.test.ts | 4 +- 27 files changed, 316 insertions(+), 97 deletions(-) create mode 100644 packages/sync/test/polling-migration.test.ts diff --git a/README.md b/README.md index 31f41fc..cb18955 100644 --- a/README.md +++ b/README.md @@ -60,9 +60,9 @@ For a compiled binary, follow the [sample entrypoint](apps/web/backend/src/entry `splitting: true`. This keeps the temporary cron process from loading the server modules. It asks the running app to process due syncs, waits for completion, and exits. -Use `sync.providers` to connect accounts. Create a destination with `sync.api.createDestination()`, -then link a source to it with `sync.api.createInstallation()`. Supply their `config` values, -a provider `connection` when needed, and `intervalMs` for the sync schedule. Pass the acting user's +Use `sync.providers` to connect accounts, then create a sync with `sync.api.createSync()`. +Supply the source `definition`, its `config`, the `destination`, and a provider `connection` +when needed. All enabled syncs poll on the shared cron schedule. Pass the acting user's `actorId` and data owner's `ownerId` from your host's authentication. See the [sample host](apps/web/backend/src/main.ts), diff --git a/apps/web/backend/src/services/dashboard/service.ts b/apps/web/backend/src/services/dashboard/service.ts index 0790683..1800b4f 100644 --- a/apps/web/backend/src/services/dashboard/service.ts +++ b/apps/web/backend/src/services/dashboard/service.ts @@ -4,7 +4,6 @@ import type { JsonObject } from '@context-use/open-sync/json'; import { BadRequestError } from '#backend/lib/errors.ts'; -const pollIntervalMs = 900_000; export type CreateSync = { source: string; config?: JsonObject; @@ -53,7 +52,6 @@ export class DashboardService { destination: input.destination, config, connection, - intervalMs: pollIntervalMs, enabled: !definition.provider || !!connection, }); // Authorization may finish in another tab between the status check and persistence. diff --git a/apps/web/frontend/src/routes/_workspace/syncs.$id.tsx b/apps/web/frontend/src/routes/_workspace/syncs.$id.tsx index 5c24168..26289f2 100644 --- a/apps/web/frontend/src/routes/_workspace/syncs.$id.tsx +++ b/apps/web/frontend/src/routes/_workspace/syncs.$id.tsx @@ -16,7 +16,6 @@ import { import { SyncAccount } from './-syncs/sync-account'; import { PendingDeliverables, PollHistory, ReceivedDeliverables } from './-syncs/sync-activity'; -const millisecondsPerMinute = 60_000; export const Route = createFileRoute('/_workspace/syncs/$id')({ validateSearch: ( search: Record, @@ -145,10 +144,6 @@ function SyncDetail() {
Status
{sync.status.replaceAll('_', ' ')}
-
Sync interval
-
{sync.intervalMs / millisecondsPerMinute} minutes
-
Next scheduled run
-
{nextRun(sync)}