From 8b0539028ee39f4520678e6ddecce7ecdfc05df7 Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Tue, 28 Oct 2025 12:17:54 +0000 Subject: [PATCH] chore: Adds a users.uuid column (#24659) * chore: Adds a users.uuid column * Add uuid backfill * Remove backfill due to possible locking issues * feat: Add batched UUID backfill to prevent database locking Implements a batched approach for backfilling UUIDs on existing users: - Processes 1000 rows at a time to avoid table locks - Uses FOR UPDATE SKIP LOCKED to prevent blocking other transactions - Includes small delays between batches (10ms) to allow other operations - Logs progress every 10,000 rows for monitoring This approach is safe for production databases with millions of users. Co-Authored-By: alex@cal.com --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> --- .../migration.sql | 48 +++++++++++++++++++ packages/prisma/schema.prisma | 1 + 2 files changed, 49 insertions(+) create mode 100644 packages/prisma/migrations/20251023133244_add_user_uuid_column/migration.sql diff --git a/packages/prisma/migrations/20251023133244_add_user_uuid_column/migration.sql b/packages/prisma/migrations/20251023133244_add_user_uuid_column/migration.sql new file mode 100644 index 0000000000..f59a6784a2 --- /dev/null +++ b/packages/prisma/migrations/20251023133244_add_user_uuid_column/migration.sql @@ -0,0 +1,48 @@ +/* + Warnings: + + - A unique constraint covering the columns `[uuid]` on the table `users` will be added. If there are existing duplicate values, this will fail. + +*/ +-- AlterTable +ALTER TABLE "public"."users" ADD COLUMN "uuid" UUID; + +-- CreateIndex +CREATE UNIQUE INDEX "users_uuid_key" ON "public"."users"("uuid"); + +-- Backfill UUIDs in batches to avoid table locking on large datasets +-- Uses FOR UPDATE SKIP LOCKED to prevent blocking other transactions +-- Processes 1000 rows at a time with small delays between batches +DO $$ +DECLARE + batch_size INT := 1000; + rows_updated INT; + total_updated INT := 0; +BEGIN + LOOP + WITH batch AS ( + SELECT id + FROM "public"."users" + WHERE uuid IS NULL + LIMIT batch_size + FOR UPDATE SKIP LOCKED + ) + UPDATE "public"."users" + SET uuid = gen_random_uuid() + FROM batch + WHERE "public"."users".id = batch.id; + + GET DIAGNOSTICS rows_updated = ROW_COUNT; + total_updated := total_updated + rows_updated; + + EXIT WHEN rows_updated = 0; + + PERFORM pg_sleep(0.01); + + IF total_updated % 10000 = 0 THEN + RAISE NOTICE 'Updated % users with UUIDs', total_updated; + END IF; + END LOOP; + + RAISE NOTICE 'Completed: Updated % total users with UUIDs', total_updated; +END $$; diff --git a/packages/prisma/schema.prisma b/packages/prisma/schema.prisma index 707c4466ec..f294889cc1 100644 --- a/packages/prisma/schema.prisma +++ b/packages/prisma/schema.prisma @@ -347,6 +347,7 @@ model TravelSchedule { // It holds Personal Profiles of a User plus it has email, password and other core things.. model User { id Int @id @default(autoincrement()) + uuid String? @unique @default(uuid()) @db.Uuid username String? name String? /// @zod.import(["import { emailSchema } from '@calcom/lib/emailSchema'"]).custom.use(emailSchema)