Skip to content

Commit 3f7a348

Browse files
committed
Fixes #71 via configuration
* parallel-updates-bug: Describe the race condition context [skip ci] Fix #71 via configuration Make Race spec self-contained Add failing spec
2 parents ee05dab + 8676248 commit 3f7a348

File tree

5 files changed

+67
-0
lines changed

5 files changed

+67
-0
lines changed

README.md

+13
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,19 @@ This is visible in `psql` if you issue a `\d+`. Example after a test run:
177177
public | test_table | view | chronomodel | 0 bytes | {"temporal":true,"journal":["foo"],"chronomodel":"0.7.0.alpha"}
178178

179179

180+
**IMPORTANT**: Rails counter cache issues an UPDATE on the parent record
181+
table, thus triggering new history entries creation. You are **strongly**
182+
advised to NOT journal the counter cache columns, or race conditions will
183+
occur (see https://github.com/ifad/chronomodel/issues/71).
184+
185+
In such cases, ensure to add `no_journal: %w( your_counter_cache_column_name )`
186+
to your `create_table`. Example:
187+
188+
create_table 'sections', temporal: true, no_journal: %w( articles_count ) do |t|
189+
t.string :name
190+
t.integer :articles_count, default: 0
191+
end
192+
180193
## Data querying
181194

182195
Include the `ChronoModel::TimeMachine` module in your model.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
require 'spec_helper'
2+
require 'support/helpers'
3+
4+
describe 'models with counter cache' do
5+
include ChronoTest::Helpers::TimeMachine
6+
7+
adapter.create_table 'sections', temporal: true, no_journal: %w( articles_count ) do |t|
8+
t.string :name
9+
t.integer :articles_count, default: 0
10+
end
11+
12+
adapter.create_table 'articles', temporal: true do |t|
13+
t.string :title
14+
t.references :section
15+
end
16+
17+
class ::Section < ActiveRecord::Base
18+
include ChronoModel::TimeMachine
19+
20+
has_many :articles
21+
end
22+
23+
class ::Article < ActiveRecord::Base
24+
include ChronoModel::TimeMachine
25+
26+
belongs_to :section, counter_cache: true
27+
end
28+
29+
describe 'are not subject to race condition if no_journal is set on the counter cache column' do
30+
specify do
31+
section = Section.create!
32+
expect(section.articles_count).to eq(0)
33+
34+
Article.create!(section_id: section.id)
35+
36+
expect(section.reload.articles_count).to eq(1)
37+
38+
num_threads = 10
39+
40+
expect do
41+
Array.new(num_threads).map do
42+
Thread.new do
43+
# sleep(rand) # With the sleep statement everything works
44+
Article.create!(section_id: section.id)
45+
end
46+
end.each(&:join)
47+
end.to_not raise_error
48+
end
49+
end
50+
end

spec/chrono_model/time_machine_spec.rb

+2
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,12 @@
8686
subject { ChronoModel.history_models }
8787

8888
it { is_expected.to eq(
89+
'articles' => Article::History,
8990
'foos' => Foo::History,
9091
'defoos' => Defoo::History,
9192
'bars' => Bar::History,
9293
'elements' => Element::History,
94+
'sections' => Section::History,
9395
'sub_bars' => SubBar::History,
9496
) }
9597
end

spec/config.travis.yml

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ hostname: localhost
22
username: postgres
33
password: ""
44
database: chronomodel
5+
pool: 11

spec/config.yml.example

+1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ hostname: localhost
55
username: chronomodel
66
password: chronomodel
77
database: chronomodel
8+
pool: 11
89
#

0 commit comments

Comments
 (0)