I don’t have anything brilliant to add here besides: yes, a database transaction.
Here’s how file race conditions are handled:
rescue Errno::ENOENT => e
$stderr.puts "No such file: /etc/passwd"
It’s important that it’s not this:
That’s a classic race condition there, where the file can disappear between the conditional and the
#read, leading to the
Errno::ENOENT bubbling up and potentially crashing the system.
Similar mindset for example (2) you gave: attempt to do the insert and handle the constraint failure exception. So in Postgres you’d add:
CREATE TABLE entries (
user_id INTEGER NOT NULL,
entry_order INTEGER NOT NULL,
UNIQUE (user_id, entry_order)
CHECK (entry_order BETWEEN 1 AND 20)
(More on StackOverflow, including a trigger: http://stackoverflow.com/questions/1743439/how-to-write-a-constraint-concerning-a-max-number-of-rows-in-postgresql )
Then you simply cannot insert invalid data.
Testing: no guaranteed way to test this from an acceptance/integration level. You can write unit tests that attempt to insert invalid data and make sure the DB doesn’t allow it.
JRuby has thread-weaver ( http://code.google.com/p/thread-weaver/ ), which might help you create a reproducable test. Have not tried it.