alephant-sequencer 3.0.2 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Guardfile +2 -2
- data/Rakefile +2 -2
- data/lib/alephant/sequencer.rb +8 -8
- data/lib/alephant/sequencer/sequence_cache.rb +24 -26
- data/lib/alephant/sequencer/sequence_table.rb +57 -64
- data/lib/alephant/sequencer/sequencer.rb +17 -17
- data/lib/alephant/sequencer/version.rb +1 -1
- data/spec/sequencer_spec.rb +80 -81
- data/spec/spec_helper.rb +4 -5
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70791cc777ca8dc9c30303150d54dab85b12c16c
|
4
|
+
data.tar.gz: 50d77f9bbc6fa698c6196e4211aa8595843eadbd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3c61f12a292ac7f7f711f7823bfa05b8ed85abf89db555942cf27dc312668decaf588597109fc48f9db0ca7e0595acd0059a3d438faaae0ee2a75581ed7b409a
|
7
|
+
data.tar.gz: 6c620cb9e6ea5174e9770714d0c46158d03582a8ee6934cccb6ac68449845d4de91f36a5795b408ab2a53bd680426b644bd6f063753e36b8b6838924b4779724
|
data/.gitignore
CHANGED
data/Guardfile
CHANGED
data/Rakefile
CHANGED
data/lib/alephant/sequencer.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require 'alephant/sequencer/version'
|
2
|
+
require 'alephant/sequencer/sequencer'
|
3
|
+
require 'alephant/sequencer/sequence_table'
|
4
|
+
require 'alephant/sequencer/sequence_cache'
|
5
5
|
|
6
6
|
module Alephant
|
7
7
|
module Sequencer
|
@@ -9,13 +9,13 @@ module Alephant
|
|
9
9
|
|
10
10
|
def self.create(table_name, opts = {})
|
11
11
|
defaults = {
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
12
|
+
jsonpath: nil,
|
13
|
+
keep_all: true,
|
14
|
+
config: {}
|
15
15
|
}
|
16
16
|
|
17
17
|
opts = defaults.merge(opts).tap do |opts|
|
18
|
-
opts[:cache] =
|
18
|
+
opts[:cache] = cache(opts[:config])
|
19
19
|
end
|
20
20
|
|
21
21
|
@@sequence_tables[table_name] ||= SequenceTable.new(table_name)
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'dalli-elasticache'
|
2
|
+
require 'alephant/logger'
|
3
3
|
|
4
4
|
module Alephant
|
5
5
|
module Sequencer
|
@@ -8,31 +8,29 @@ module Alephant
|
|
8
8
|
|
9
9
|
attr_reader :config
|
10
10
|
|
11
|
-
DEFAULT_TTL
|
11
|
+
DEFAULT_TTL = 2
|
12
12
|
|
13
|
-
def initialize(config={})
|
13
|
+
def initialize(config = {})
|
14
14
|
@config = config
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
else
|
20
|
-
logger.debug "Alephant::SequenceCache::#initialize: No config endpoint, NullClient used"
|
21
|
-
logger.metric "NoConfigEndpoint"
|
16
|
+
if config_endpoint.nil?
|
17
|
+
logger.debug 'Alephant::SequenceCache::#initialize: No config endpoint, NullClient used'
|
18
|
+
logger.metric 'NoConfigEndpoint'
|
22
19
|
@client = NullClient.new
|
20
|
+
else
|
21
|
+
@elasticache ||= ::Dalli::ElastiCache.new(config_endpoint, expires_in: ttl)
|
22
|
+
@client ||= @elasticache.client
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
def get(key
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
block.call
|
35
|
-
end
|
26
|
+
def get(key)
|
27
|
+
versioned_key = versioned key
|
28
|
+
result = @client.get versioned_key
|
29
|
+
logger.info "Alephant::SequenceCache#get key: #{versioned_key} - #{result ? 'hit' : 'miss'}"
|
30
|
+
logger.metric 'GetKeyMiss' unless result
|
31
|
+
result ? result : set(key, yield)
|
32
|
+
rescue StandardError => e
|
33
|
+
yield
|
36
34
|
end
|
37
35
|
|
38
36
|
def set(key, value, ttl = nil)
|
@@ -42,28 +40,28 @@ module Alephant
|
|
42
40
|
private
|
43
41
|
|
44
42
|
def config_endpoint
|
45
|
-
config[
|
43
|
+
config[:elasticache_config_endpoint] || config['elasticache_config_endpoint']
|
46
44
|
end
|
47
45
|
|
48
46
|
def ttl
|
49
|
-
config[
|
47
|
+
config[:sequencer_elasticache_ttl] || config['sequencer_elasticache_ttl'] || DEFAULT_TTL
|
50
48
|
end
|
51
49
|
|
52
50
|
def versioned(key)
|
53
|
-
[key, cache_version].compact.join(
|
51
|
+
[key, cache_version].compact.join('_')
|
54
52
|
end
|
55
53
|
|
56
54
|
def cache_version
|
57
|
-
config[
|
55
|
+
config[:elasticache_cache_version] || config['elasticache_cache_version']
|
58
56
|
end
|
59
57
|
end
|
60
58
|
|
61
59
|
class NullClient
|
62
60
|
def get(key); end
|
63
61
|
|
64
|
-
def set(
|
62
|
+
def set(_key, value, _ttl = nil)
|
65
63
|
value
|
66
64
|
end
|
67
65
|
end
|
68
66
|
end
|
69
|
-
end
|
67
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require 'aws-sdk'
|
2
|
+
require 'thread'
|
3
|
+
require 'timeout'
|
4
4
|
|
5
|
-
require
|
6
|
-
require
|
5
|
+
require 'alephant/logger'
|
6
|
+
require 'alephant/support/dynamodb/table'
|
7
7
|
|
8
8
|
module Alephant
|
9
9
|
module Sequencer
|
@@ -18,13 +18,11 @@ module Alephant
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def sequence_exists(ident)
|
21
|
-
if ident.nil?
|
22
|
-
return false
|
23
|
-
end
|
21
|
+
return false if ident.nil?
|
24
22
|
|
25
|
-
!
|
23
|
+
!client.get_item(
|
26
24
|
item_payload(ident)
|
27
|
-
).
|
25
|
+
).empty?
|
28
26
|
end
|
29
27
|
|
30
28
|
def sequence_for(ident)
|
@@ -32,62 +30,58 @@ module Alephant
|
|
32
30
|
item_payload(ident)
|
33
31
|
)
|
34
32
|
|
35
|
-
data.
|
33
|
+
!data.empty? ? data[:item]['value'][:n].to_i : 0
|
36
34
|
end
|
37
35
|
|
38
36
|
def update_sequence_id(ident, value, last_seen_check = nil)
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
:conditional_operator => 'OR'
|
65
|
-
})
|
66
|
-
end
|
67
|
-
|
68
|
-
logger.metric("SequencerFailedConditionalChecks", :value => 0)
|
69
|
-
logger.info(
|
70
|
-
"event" => "SequenceIdUpdated",
|
71
|
-
"id" => ident,
|
72
|
-
"value" => value,
|
73
|
-
"method" => "#{self.class}#update_sequence_id"
|
74
|
-
)
|
37
|
+
current_sequence = last_seen_check.nil? ? sequence_for(ident) : last_seen_check
|
38
|
+
|
39
|
+
dynamo_response = @mutex.synchronize do
|
40
|
+
client.put_item(table_name: table_name,
|
41
|
+
item: {
|
42
|
+
'key' => {
|
43
|
+
'S' => ident
|
44
|
+
},
|
45
|
+
'value' => {
|
46
|
+
'N' => value.to_s
|
47
|
+
}
|
48
|
+
},
|
49
|
+
expected: {
|
50
|
+
'key' => {
|
51
|
+
comparison_operator: 'NULL'
|
52
|
+
},
|
53
|
+
'value' => {
|
54
|
+
comparison_operator: 'GE',
|
55
|
+
attribute_value_list: [
|
56
|
+
{ 'N' => current_sequence.to_s }
|
57
|
+
]
|
58
|
+
}
|
59
|
+
},
|
60
|
+
conditional_operator: 'OR')
|
61
|
+
end
|
75
62
|
|
76
|
-
|
63
|
+
logger.metric('SequencerFailedConditionalChecks', value: 0)
|
64
|
+
logger.info(
|
65
|
+
'event' => 'SequenceIdUpdated',
|
66
|
+
'id' => ident,
|
67
|
+
'value' => value,
|
68
|
+
'method' => "#{self.class}#update_sequence_id"
|
69
|
+
)
|
77
70
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
)
|
90
|
-
|
71
|
+
dynamo_response
|
72
|
+
|
73
|
+
rescue AWS::DynamoDB::Errors::ConditionalCheckFailedException
|
74
|
+
logger.metric 'SequencerFailedConditionalChecks'
|
75
|
+
logger.error(
|
76
|
+
'event' => 'DynamoDBConditionalCheckFailed',
|
77
|
+
'newSequenceValue' => value,
|
78
|
+
'currentSequenceValue' => current_sequence,
|
79
|
+
'id' => ident,
|
80
|
+
'class' => e.class,
|
81
|
+
'message' => e.message,
|
82
|
+
'backtrace' => e.backtrace.join("\n"),
|
83
|
+
'method' => "#{self.class}#update_sequence_id"
|
84
|
+
)
|
91
85
|
end
|
92
86
|
|
93
87
|
def delete_item!(ident)
|
@@ -100,15 +94,14 @@ module Alephant
|
|
100
94
|
|
101
95
|
def item_payload(ident)
|
102
96
|
{
|
103
|
-
:
|
104
|
-
:
|
97
|
+
table_name: table_name,
|
98
|
+
key: {
|
105
99
|
'key' => {
|
106
100
|
'S' => ident.to_s
|
107
101
|
}
|
108
102
|
}
|
109
103
|
}
|
110
104
|
end
|
111
|
-
|
112
105
|
end
|
113
106
|
end
|
114
107
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'jsonpath'
|
2
|
+
require 'alephant/logger'
|
3
3
|
|
4
4
|
module Alephant
|
5
5
|
module Sequencer
|
@@ -16,11 +16,11 @@ module Alephant
|
|
16
16
|
@exists = exists?
|
17
17
|
@jsonpath = opts[:jsonpath]
|
18
18
|
logger.info(
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
'event' => 'SequencerInitialized',
|
20
|
+
'sequenceTable' => sequence_table,
|
21
|
+
'jsonPath' => @jsonpath,
|
22
|
+
'id' => @ident,
|
23
|
+
'method' => "#{self.class}#initialize"
|
24
24
|
)
|
25
25
|
end
|
26
26
|
|
@@ -34,21 +34,21 @@ module Alephant
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
def validate(msg
|
37
|
+
def validate(msg)
|
38
38
|
last_seen_id = get_last_seen
|
39
39
|
sequential = ((last_seen_id || 0) < Sequencer.sequence_id_from(msg, jsonpath))
|
40
40
|
|
41
|
-
|
41
|
+
yield if sequential || keep_all
|
42
42
|
|
43
43
|
if sequential
|
44
44
|
set_last_seen(msg, last_seen_id)
|
45
45
|
else
|
46
|
-
logger.metric
|
46
|
+
logger.metric 'SequencerNonSequentialMessageCount'
|
47
47
|
logger.info(
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
'event' => 'NonSequentialMessageReceived',
|
49
|
+
'id' => ident,
|
50
|
+
'lastSeenId' => last_seen_id,
|
51
|
+
'method' => "#{self.class}#validate"
|
52
52
|
)
|
53
53
|
end
|
54
54
|
end
|
@@ -57,9 +57,9 @@ module Alephant
|
|
57
57
|
@exists = false
|
58
58
|
@sequence_table.delete_item!(ident).tap do
|
59
59
|
logger.info(
|
60
|
-
|
61
|
-
|
62
|
-
|
60
|
+
'event' => 'SequenceIdDeleted',
|
61
|
+
'id' => ident,
|
62
|
+
'method' => "#{self.class}#delete!"
|
63
63
|
)
|
64
64
|
end
|
65
65
|
end
|
data/spec/sequencer_spec.rb
CHANGED
@@ -1,23 +1,23 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Alephant::Sequencer do
|
4
4
|
let(:ident) { :ident }
|
5
|
-
let(:jsonpath) {
|
5
|
+
let(:jsonpath) { '$.sequence_id' }
|
6
6
|
let(:sequence_table) { double(Alephant::Sequencer::SequenceTable) }
|
7
7
|
let(:keep_all) { true }
|
8
|
-
let(:config) { {
|
8
|
+
let(:config) { { 'elasticache_config_endpoint' => '/foo' } }
|
9
9
|
let(:cache) { Alephant::Sequencer::SequenceCache.new(config) }
|
10
|
-
let(:opts)
|
10
|
+
let(:opts) do
|
11
11
|
{
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:cache
|
12
|
+
id: ident,
|
13
|
+
jsonpath: jsonpath,
|
14
|
+
keep_all: keep_all,
|
15
|
+
cache: cache
|
16
16
|
}
|
17
|
-
|
17
|
+
end
|
18
18
|
|
19
|
-
describe
|
20
|
-
it
|
19
|
+
describe '.create' do
|
20
|
+
it 'should return a Sequencer' do
|
21
21
|
expect_any_instance_of(Dalli::ElastiCache).to receive(:initialize)
|
22
22
|
expect_any_instance_of(Dalli::ElastiCache).to receive(:client).and_return(Dalli::Client.new)
|
23
23
|
|
@@ -25,20 +25,20 @@ describe Alephant::Sequencer do
|
|
25
25
|
expect_any_instance_of(Alephant::Sequencer::SequenceTable).to receive(:sequence_exists)
|
26
26
|
|
27
27
|
opts = {
|
28
|
-
:
|
29
|
-
:
|
30
|
-
:
|
31
|
-
:config
|
28
|
+
id: ident,
|
29
|
+
jsonpath: jsonpath,
|
30
|
+
keep_all: keep_all,
|
31
|
+
config: config
|
32
32
|
}
|
33
33
|
|
34
34
|
expect(subject.create(:table_name, opts)).to be_a Alephant::Sequencer::Sequencer
|
35
35
|
end
|
36
36
|
|
37
|
-
it
|
37
|
+
it 'should use default opts if options not provided' do
|
38
38
|
expect_any_instance_of(Alephant::Sequencer::SequenceTable).to receive(:sequence_exists)
|
39
39
|
|
40
40
|
opts = {
|
41
|
-
:
|
41
|
+
id: ident
|
42
42
|
}
|
43
43
|
|
44
44
|
instance = subject.create(:table_name, opts)
|
@@ -52,15 +52,15 @@ describe Alephant::Sequencer do
|
|
52
52
|
end
|
53
53
|
|
54
54
|
describe Alephant::Sequencer::Sequencer do
|
55
|
-
let(:data) { double
|
55
|
+
let(:data) { double }
|
56
56
|
let(:last_seen) { 42 }
|
57
57
|
|
58
|
-
describe
|
59
|
-
subject (:instance)
|
58
|
+
describe '#initialize' do
|
59
|
+
subject (:instance) do
|
60
60
|
described_class.new(sequence_table, opts)
|
61
|
-
|
61
|
+
end
|
62
62
|
|
63
|
-
it
|
63
|
+
it 'sets @jsonpath, @ident' do
|
64
64
|
expect(sequence_table).to receive(:sequence_exists)
|
65
65
|
|
66
66
|
expect_any_instance_of(Dalli::ElastiCache).to receive(:initialize)
|
@@ -70,26 +70,25 @@ describe Alephant::Sequencer do
|
|
70
70
|
expect(instance.ident).to eq(ident)
|
71
71
|
expect(instance.keep_all).to eq(true)
|
72
72
|
end
|
73
|
-
|
74
73
|
end
|
75
74
|
|
76
|
-
describe
|
77
|
-
let(:message) { double
|
75
|
+
describe '#validate' do
|
76
|
+
let(:message) { double }
|
78
77
|
|
79
78
|
let(:an_uncalled_proc) do
|
80
|
-
a_block = double
|
79
|
+
a_block = double
|
81
80
|
expect(a_block).to_not receive(:called).with(message)
|
82
81
|
|
83
|
-
|
82
|
+
proc do |msg|
|
84
83
|
a_block.called(msg)
|
85
84
|
end
|
86
85
|
end
|
87
86
|
|
88
87
|
let(:a_proc) do
|
89
|
-
a_block = double
|
88
|
+
a_block = double
|
90
89
|
expect(a_block).to receive(:called)
|
91
90
|
|
92
|
-
|
91
|
+
proc do
|
93
92
|
a_block.called
|
94
93
|
end
|
95
94
|
end
|
@@ -98,11 +97,11 @@ describe Alephant::Sequencer do
|
|
98
97
|
let(:stubbed_seen_high) { 3 }
|
99
98
|
let(:stubbed_seen_low) { 1 }
|
100
99
|
|
101
|
-
subject (:instance)
|
100
|
+
subject (:instance) do
|
102
101
|
described_class.new(sequence_table, opts)
|
103
|
-
|
102
|
+
end
|
104
103
|
|
105
|
-
it
|
104
|
+
it 'should call the passed block' do
|
106
105
|
expect(sequence_table).to receive(:sequence_exists)
|
107
106
|
expect(sequence_table).to receive(:sequence_for).with(ident)
|
108
107
|
|
@@ -117,7 +116,7 @@ describe Alephant::Sequencer do
|
|
117
116
|
instance.validate(message, &a_proc)
|
118
117
|
end
|
119
118
|
|
120
|
-
context
|
119
|
+
context 'last_seen_id is nil' do
|
121
120
|
before(:each) do
|
122
121
|
expect_any_instance_of(described_class).to receive(:get_last_seen).and_return(nil)
|
123
122
|
|
@@ -130,7 +129,7 @@ describe Alephant::Sequencer do
|
|
130
129
|
expect_any_instance_of(Dalli::Client).to receive(:set)
|
131
130
|
end
|
132
131
|
|
133
|
-
it
|
132
|
+
it 'should not call set_last_seen' do
|
134
133
|
expect_any_instance_of(described_class).to receive(:set_last_seen).with(message, nil)
|
135
134
|
|
136
135
|
expect(sequence_table).to receive(:sequence_exists)
|
@@ -139,7 +138,7 @@ describe Alephant::Sequencer do
|
|
139
138
|
end
|
140
139
|
end
|
141
140
|
|
142
|
-
context
|
141
|
+
context 'last_seen_id == sequence_id_from(msg)' do
|
143
142
|
before(:each) do
|
144
143
|
expect_any_instance_of(described_class).to receive(:get_last_seen).and_return(stubbed_last_seen)
|
145
144
|
|
@@ -152,7 +151,7 @@ describe Alephant::Sequencer do
|
|
152
151
|
expect_any_instance_of(Dalli::Client).to receive(:set)
|
153
152
|
end
|
154
153
|
|
155
|
-
it
|
154
|
+
it 'should not call set_last_seen(msg, last_seen_id)' do
|
156
155
|
expect_any_instance_of(described_class).to_not receive(:set_last_seen)
|
157
156
|
|
158
157
|
expect(sequence_table).to receive(:sequence_exists)
|
@@ -161,7 +160,7 @@ describe Alephant::Sequencer do
|
|
161
160
|
end
|
162
161
|
end
|
163
162
|
|
164
|
-
context
|
163
|
+
context 'last_seen_id > sequence_id_from(msg)' do
|
165
164
|
before(:each) do
|
166
165
|
expect_any_instance_of(described_class).to receive(:get_last_seen).and_return(stubbed_last_seen)
|
167
166
|
|
@@ -174,7 +173,7 @@ describe Alephant::Sequencer do
|
|
174
173
|
expect_any_instance_of(Dalli::Client).to receive(:set)
|
175
174
|
end
|
176
175
|
|
177
|
-
it
|
176
|
+
it 'should not call set_last_seen' do
|
178
177
|
expect_any_instance_of(described_class).to_not receive(:set_last_seen)
|
179
178
|
|
180
179
|
expect(sequence_table).to receive(:sequence_exists)
|
@@ -182,17 +181,17 @@ describe Alephant::Sequencer do
|
|
182
181
|
instance.validate(message, &a_proc)
|
183
182
|
end
|
184
183
|
|
185
|
-
context
|
184
|
+
context 'keep_all is false' do
|
186
185
|
let(:keep_all) { false }
|
187
186
|
|
188
|
-
it
|
187
|
+
it 'should not call the passed block with msg' do
|
189
188
|
expect(sequence_table).to receive(:sequence_exists)
|
190
189
|
|
191
190
|
opts = {
|
192
|
-
:
|
193
|
-
:
|
194
|
-
:
|
195
|
-
:cache
|
191
|
+
id: ident,
|
192
|
+
jsonpath: jsonpath,
|
193
|
+
keep_all: keep_all,
|
194
|
+
cache: cache
|
196
195
|
}
|
197
196
|
|
198
197
|
instance = described_class.new(sequence_table, opts)
|
@@ -201,7 +200,7 @@ describe Alephant::Sequencer do
|
|
201
200
|
end
|
202
201
|
end
|
203
202
|
|
204
|
-
context
|
203
|
+
context 'last_seen_id < sequence_id_from(msg)' do
|
205
204
|
before(:each) do
|
206
205
|
expect_any_instance_of(described_class).to receive(:get_last_seen).and_return(stubbed_last_seen)
|
207
206
|
|
@@ -214,7 +213,7 @@ describe Alephant::Sequencer do
|
|
214
213
|
expect_any_instance_of(Dalli::Client).to receive(:set)
|
215
214
|
end
|
216
215
|
|
217
|
-
it
|
216
|
+
it 'should call set_last_seen(msg, last_seen_id)' do
|
218
217
|
expect_any_instance_of(described_class).to receive(:set_last_seen).with(message, stubbed_last_seen)
|
219
218
|
|
220
219
|
expect(sequence_table).to receive(:sequence_exists)
|
@@ -223,18 +222,18 @@ describe Alephant::Sequencer do
|
|
223
222
|
end
|
224
223
|
end
|
225
224
|
|
226
|
-
context
|
225
|
+
context 'values already in cache' do
|
227
226
|
before(:each) do
|
228
|
-
expect(message).to receive(:body).and_return(
|
227
|
+
expect(message).to receive(:body).and_return('sequence_id' => 5)
|
229
228
|
|
230
229
|
expect_any_instance_of(Dalli::ElastiCache).to receive(:initialize)
|
231
230
|
expect_any_instance_of(Dalli::ElastiCache).to receive(:client).and_return(Dalli::Client.new)
|
232
231
|
|
233
|
-
expect_any_instance_of(Dalli::Client).to receive(:get).twice.with(
|
232
|
+
expect_any_instance_of(Dalli::Client).to receive(:get).twice.with('ident').and_return(stubbed_last_seen)
|
234
233
|
expect_any_instance_of(Dalli::Client).to_not receive(:set)
|
235
234
|
end
|
236
235
|
|
237
|
-
it
|
236
|
+
it 'should read values from cache and not database' do
|
238
237
|
expect(sequence_table).to_not receive(:sequence_for)
|
239
238
|
expect(sequence_table).to_not receive(:sequence_exists)
|
240
239
|
|
@@ -245,12 +244,12 @@ describe Alephant::Sequencer do
|
|
245
244
|
end
|
246
245
|
end
|
247
246
|
|
248
|
-
describe
|
249
|
-
subject (:instance)
|
247
|
+
describe '#get_last_seen' do
|
248
|
+
subject (:instance) do
|
250
249
|
described_class.new(sequence_table, opts)
|
251
|
-
|
250
|
+
end
|
252
251
|
|
253
|
-
it
|
252
|
+
it 'returns sequence_table.sequence_for(ident)' do
|
254
253
|
expect_any_instance_of(Dalli::ElastiCache).to receive(:initialize)
|
255
254
|
expect_any_instance_of(Dalli::ElastiCache).to receive(:client).and_return(Dalli::Client.new)
|
256
255
|
|
@@ -267,7 +266,7 @@ describe Alephant::Sequencer do
|
|
267
266
|
end
|
268
267
|
end
|
269
268
|
|
270
|
-
describe
|
269
|
+
describe '#set_last_seen' do
|
271
270
|
before(:each) do
|
272
271
|
expect(described_class).to receive(:sequence_id_from).and_return(last_seen)
|
273
272
|
|
@@ -278,11 +277,11 @@ describe Alephant::Sequencer do
|
|
278
277
|
expect_any_instance_of(Dalli::Client).to receive(:set).twice
|
279
278
|
end
|
280
279
|
|
281
|
-
subject (:instance)
|
280
|
+
subject (:instance) do
|
282
281
|
described_class.new(sequence_table, opts)
|
283
|
-
|
282
|
+
end
|
284
283
|
|
285
|
-
it
|
284
|
+
it 'calls update_sequence_id(ident, last_seen)' do
|
286
285
|
expect(sequence_table).to receive(:sequence_exists).twice
|
287
286
|
|
288
287
|
expect(sequence_table).to receive(:update_sequence_id)
|
@@ -292,20 +291,20 @@ describe Alephant::Sequencer do
|
|
292
291
|
end
|
293
292
|
end
|
294
293
|
|
295
|
-
describe
|
296
|
-
it
|
297
|
-
msg = Struct.new(:body).new(
|
294
|
+
describe '.sequence_id_from' do
|
295
|
+
it 'should return the id described by the set jsonpath' do
|
296
|
+
msg = Struct.new(:body).new('set_sequence_id' => 1)
|
298
297
|
|
299
|
-
expect(described_class.sequence_id_from(msg,
|
298
|
+
expect(described_class.sequence_id_from(msg, '$.set_sequence_id')).to eq(1)
|
300
299
|
end
|
301
300
|
end
|
302
301
|
|
303
|
-
describe
|
302
|
+
describe '#sequential?' do
|
304
303
|
before(:each) do
|
305
304
|
expect_any_instance_of(described_class).to receive(:get_last_seen).and_return(1)
|
306
305
|
|
307
306
|
expect(data).to receive(:body)
|
308
|
-
.and_return(
|
307
|
+
.and_return('sequence_id' => id_value)
|
309
308
|
|
310
309
|
expect(sequence_table).to receive(:sequence_exists)
|
311
310
|
|
@@ -316,57 +315,57 @@ describe Alephant::Sequencer do
|
|
316
315
|
expect_any_instance_of(Dalli::Client).to receive(:set)
|
317
316
|
end
|
318
317
|
|
319
|
-
subject (:instance)
|
318
|
+
subject (:instance) do
|
320
319
|
described_class.new(sequence_table, opts)
|
321
|
-
|
320
|
+
end
|
322
321
|
|
323
322
|
context "jsonpath = '$.sequence_id'" do
|
324
|
-
let(:jsonpath) {
|
323
|
+
let(:jsonpath) { '$.sequence_id' }
|
325
324
|
|
326
|
-
context
|
325
|
+
context 'sequential' do
|
327
326
|
let(:id_value) { 2 }
|
328
327
|
|
329
|
-
it
|
328
|
+
it 'is true' do
|
330
329
|
expect(instance.sequential?(data)).to be
|
331
330
|
end
|
332
331
|
end
|
333
332
|
|
334
|
-
context
|
333
|
+
context 'nonsequential' do
|
335
334
|
let(:id_value) { 0 }
|
336
335
|
|
337
|
-
it
|
336
|
+
it 'is false' do
|
338
337
|
expect(instance.sequential?(data)).to be false
|
339
338
|
end
|
340
339
|
end
|
341
340
|
end
|
342
341
|
|
343
|
-
context
|
344
|
-
let(:jsonpath) {
|
342
|
+
context 'jsonpath = nil' do
|
343
|
+
let(:jsonpath) { '$.sequence_id' }
|
345
344
|
|
346
|
-
context
|
345
|
+
context 'sequential' do
|
347
346
|
let(:id_value) { 2 }
|
348
347
|
|
349
|
-
it
|
348
|
+
it 'is true' do
|
350
349
|
expect(instance.sequential?(data)).to be
|
351
350
|
end
|
352
351
|
end
|
353
352
|
|
354
|
-
context
|
353
|
+
context 'nonsequential' do
|
355
354
|
let(:id_value) { 0 }
|
356
355
|
|
357
|
-
it
|
356
|
+
it 'is false' do
|
358
357
|
expect(instance.sequential?(data)).to be false
|
359
358
|
end
|
360
359
|
end
|
361
360
|
end
|
362
361
|
end
|
363
362
|
|
364
|
-
describe
|
365
|
-
subject (:instance)
|
363
|
+
describe '#truncate!' do
|
364
|
+
subject (:instance) do
|
366
365
|
described_class.new(sequence_table, opts)
|
367
|
-
|
366
|
+
end
|
368
367
|
|
369
|
-
it
|
368
|
+
it 'verify SequenceTable#truncate!' do
|
370
369
|
expect_any_instance_of(Dalli::ElastiCache).to receive(:initialize)
|
371
370
|
expect_any_instance_of(Dalli::ElastiCache).to receive(:client).and_return(Dalli::Client.new)
|
372
371
|
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require "pry"
|
4
|
-
require "alephant/sequencer"
|
5
|
-
require "alephant/support"
|
1
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
|
6
2
|
|
3
|
+
require 'pry'
|
4
|
+
require 'alephant/sequencer'
|
5
|
+
require 'alephant/support'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alephant-sequencer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.0.
|
4
|
+
version: 3.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- BBC News
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-05-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|