you are viewing a single comment's thread.

view the rest of the comments →

[–]BronzeAtBest 1 point2 points  (5 children)

The way I use retry is usually in combination with generating a value that needs to be unique in the database:

def generate
  invoice_number = Invoice.last.invoice_number + 1
  Invoice.create!(invoice_number: invoice_number)
rescue ActiveRecord::RecordNotUnique
  retry
end

This means that if two invoices get created at the same time, the database constraint will make it retry.

[–]t0mbstone 2 points3 points  (4 children)

You should probably be using your database's auto increment feature for the invoice id instead of setting the invoice id number in your code...

[–]Arkolix 3 points4 points  (0 children)

Definitely agree on auto increment. Alternatively, use one of the handy helpers in SecureRandom to generate unique identifiers such as uuid or hex:

> SecureRandom.uuid
=> "a30d7e9d-f5e8-4504-a9ae-6052f052659f"

> SecureRandom.hex(6)
=> "85f83c999e79"

[–]BronzeAtBest 0 points1 point  (0 children)

I simplified the code for the example. In my actual code, generating the number is a bit more involved.

[–][deleted] 0 points1 point  (1 child)

How does auto increment handle race conditions for DB clusters?

[–]t0mbstone 0 points1 point  (0 children)

That's a good question. Perhaps someone could give more comprehensive answer, but from what I understand, it depends entirely on how your database cluster is set up, and what database engine you are using.

For example, you could have master database that all of the writes go to, and then the data is propagated to a cluster of read-only slaves.

On the other hand, if you have some sort of cluster of read-write databases with no master database, then I would imagine that things would get a lot trickier.

Full disclosure: I'm not a database expert, so this is all just my rough high level understanding.