diff --git a/backend/mpc-system/services/session-coordinator/adapters/output/postgres/session_postgres_repo.go b/backend/mpc-system/services/session-coordinator/adapters/output/postgres/session_postgres_repo.go index 22ca2c4c..323a9089 100644 --- a/backend/mpc-system/services/session-coordinator/adapters/output/postgres/session_postgres_repo.go +++ b/backend/mpc-system/services/session-coordinator/adapters/output/postgres/session_postgres_repo.go @@ -265,34 +265,66 @@ func (r *SessionPostgresRepo) Update(ctx context.Context, session *entities.MPCS return err } - // Upsert participants (insert or update) + // Update each participant individually using UPDATE to avoid lost updates + // Using individual UPDATE statements ensures concurrent updates to different participants don't conflict for _, p := range session.Participants { - _, err = tx.ExecContext(ctx, ` - INSERT INTO participants ( - id, session_id, party_id, party_index, status, - device_type, device_id, platform, app_version, public_key, joined_at, completed_at - ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) - ON CONFLICT (session_id, party_id) DO UPDATE SET - status = EXCLUDED.status, - public_key = EXCLUDED.public_key, - completed_at = EXCLUDED.completed_at + // Try UPDATE first + result, err := tx.ExecContext(ctx, ` + UPDATE participants SET + status = $1, + public_key = $2, + completed_at = $3, + device_type = $4, + device_id = $5, + platform = $6, + app_version = $7 + WHERE session_id = $8 AND party_id = $9 `, - uuid.New(), - session.ID.UUID(), - p.PartyID.String(), - p.PartyIndex, p.Status.String(), + p.PublicKey, + p.CompletedAt, p.DeviceInfo.DeviceType, p.DeviceInfo.DeviceID, p.DeviceInfo.Platform, p.DeviceInfo.AppVersion, - p.PublicKey, - p.JoinedAt, - p.CompletedAt, + session.ID.UUID(), + p.PartyID.String(), ) if err != nil { return err } + + // If no rows affected, participant doesn't exist yet, INSERT it + rowsAffected, err := result.RowsAffected() + if err != nil { + return err + } + + if rowsAffected == 0 { + // Participant doesn't exist, INSERT it + _, err = tx.ExecContext(ctx, ` + INSERT INTO participants ( + id, session_id, party_id, party_index, status, + device_type, device_id, platform, app_version, public_key, joined_at, completed_at + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) + `, + uuid.New(), + session.ID.UUID(), + p.PartyID.String(), + p.PartyIndex, + p.Status.String(), + p.DeviceInfo.DeviceType, + p.DeviceInfo.DeviceID, + p.DeviceInfo.Platform, + p.DeviceInfo.AppVersion, + p.PublicKey, + p.JoinedAt, + p.CompletedAt, + ) + if err != nil { + return err + } + } } return tx.Commit()