conradkohC
Convex Community2y ago
4 replies
conradkoh

Race condition when reading and writing data

I encountered a race condition somewhere in my code and I can't figure out where my understanding is lacking in how convex handles concurrent write requests. This is the query for my code, where I am attempting to use convex as a cache, while I am migrating my system over.

The way it works is that my system will call convex to update the cache when the data in my other backend changes. The frontend is subscribed to convex as the source of truth.

/**
 * This should be called by the server
 */
export const update = mutation({
  args: {
    accessTokenHash: v.string(),
    userId: v.string(),
    accounts: v.array(AccountValue()),
  },
  handler: async (ctx, args) => {
    const tokenHash = args.accessTokenHash;

    //invalidate all other user accounts caches
    const caches = await ctx.db
      .query('cache_userAccounts')
      .withIndex('by_userId', (q) => q.eq('userId', args.userId))
      .collect();

    //grant access to updater
    const existsForToken =
      caches.find(
        (v) => v.tokenHash === tokenHash && v.userId == args.userId
      ) != undefined;
    if (!existsForToken) {
      await ctx.db.insert('cache_userAccounts', {
        tokenHash: tokenHash,
        userId: args.userId,
        accounts: args.accounts,
      });
    }

    //update all caches
    await Promise.allSettled(
      caches.map(async (cache) => {
        await ctx.db.patch(cache._id, {
          tokenHash: tokenHash,
          userId: args.userId,
          accounts: args.accounts,
        });
      })
    );
  },
});


The issue I am facing is that existsForToken returns false and multiple repeated rows are inserted into the table, with the same tokenHash and userId. my intent is for the tokenHash + userId to for a unique pair.

I've seen some other threads where .withIndex(<index name>).unique() was suggested, but I don't really see how .unique() is helpful, because this errors out on read (aka the data is already in an inconsistent state).
Was this page helpful?