`contended transaction` error

Transaction was aborted due to detection of concurrent modification

I have tried searching for this and what to do, but have not seen anything.

There are no ‘unique’ indexes involved here. Should I be doing something at application level to avoid concurrent writes?

The query in question:

await this.client.query(
    q.Let(
        {
            logMeta: q.Select(['ref'], q.Get(
                q.Documents(q.Collection('log_meta')),
            )),
            doc: q.Match(
                q.Index('action_by_id'),
                [id]
            ),
        },
        q.If(
            q.Exists(q.Var('doc')),
            q.Abort('That ID already exists'),
            q.Do([
                q.Update(
                    q.Var('logMeta'),
                    {
                        data: {
                            last_added: q.Add(q.Select(
                                ['data', 'last_added'],
                                q.Get(q.Var('logMeta'))
                            ), 1)
                        }
                    }
                ),
                q.Create(
                    q.Collection('actions'),
                    { data: entry }
                ),
            ])
        )
    )
)

Hi @nichoth.

Contention refers to a transaction vying for control of a document or index but that keep changing.

In this topic, I go through a step-by-step scenario of contention.

It looks like you are reading a document and trying to update it with a new value (increment it by 1). If there are too many requests made simultaneously then that will most assuredly cause contention.

For something like this counter, or “reactions” (think likes on Facebook, or counting number of retweets), or similar updates that can happen in bursts, you may need to consider something like the “Event Sourcing Pattern” described here: This tutorial describes a strategy for reducing database contention in high write throughput situations. - Fauna Documentation. It’s written with FQL v4 in mind, but the concept still applies to FQL v10.

Speaking of FQL v10, you might find a query like this easier to read. It will still have the same issue with contention, though.

// v10
let logMeta = log_meta.all().first()!
let doc = actions.by_id(${id}) // assuming new v10 index added to `actions` collection.

if (doc.exists()) {
  abort("That ID already exists")
}

logMeta.update({ last_added: logMeta.last_added + 1 })
actions.create(${entry})
1 Like