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
9 changes: 6 additions & 3 deletions .github/workflows/test-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,14 @@ jobs:
working-directory: packages/db
run: bun run db:migrate

- name: Verify retired-column contract migration in PostgreSQL
- name: Verify schema contract migrations in PostgreSQL
working-directory: packages/db
env:
RETIRED_COLUMNS_TEST_DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/sim_auth_scim
run: bunx vitest run scripts/retired-columns.postgres.test.ts
MIGRATION_CONTRACT_TEST_DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/sim_auth_scim
run: >-
bunx vitest run
scripts/retired-columns.postgres.test.ts
scripts/connector-sync-schedule-precision.postgres.test.ts

- name: Verify OAuth lifecycle and SCIM membership guards in PostgreSQL
working-directory: apps/sim
Expand Down
10 changes: 9 additions & 1 deletion apps/sim/lib/knowledge/connectors/member-queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ async function describeUnacceptedMemberSync(
memberSyncStatus: knowledgeConnector.memberSyncStatus,
nextMemberSyncAt: knowledgeConnector.nextMemberSyncAt,
syncLockToken: knowledgeConnector.syncLockToken,
memberSyncLockToken: knowledgeConnector.memberSyncLockToken,
archivedAt: knowledgeConnector.archivedAt,
deletedAt: knowledgeConnector.deletedAt,
})
Expand All @@ -181,7 +182,14 @@ async function describeUnacceptedMemberSync(
) {
return 'The member sync schedule changed after this run was scheduled'
}
return 'A member sync is already queued or running for this connector'
if (row.memberSyncLockToken) {
return 'A member sync is already queued or running for this connector'
}
/**
* No checked condition explains the refusal. Naming a cause here instead once hid a connector
* that was refused on every attempt for days, because the reason read as ordinary contention.
*/
return 'The connector refused the claim while no lock or status explains it'
}

/**
Expand Down
16 changes: 16 additions & 0 deletions packages/db/migrations/0363_connector_sync_schedule_precision.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-- The scheduler round-trips these schedules through a JavaScript `Date` and claims a run by
-- matching the value back exactly. `Date` carries milliseconds while PostgreSQL stores
-- microseconds, so a schedule written in SQL rather than by the application became unmatchable the
-- moment it landed on a fractional millisecond: the connector stayed permanently due and every
-- claim was refused. Narrowing to the precision the round trip can carry makes both ends compare
-- the same value, and rounds the stored values so an already-wedged row recovers. Both columns are
-- narrowed in one statement so the rewrite is a single pass. `knowledge_connector_member`'s
-- `next_attempt_at` is written by the same backfill but is only ever range-compared, never claimed
-- by equality, so it is left alone.
--
-- migration-safe: every deployed reader and writer of these columns goes through a JavaScript
-- `Date`, which already truncates to milliseconds, so the discarded precision is unobservable to
-- the running version and this needs no earlier deploy.
ALTER TABLE "knowledge_connector"
ALTER COLUMN "next_member_sync_at" SET DATA TYPE timestamp (3),
ALTER COLUMN "next_sync_at" SET DATA TYPE timestamp (3);
Loading
Loading