dyna_model 0.0.8 → 0.0.9

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2739ba4513b27ea83ebe29ba3de12d9a3f96f1b0
4
- data.tar.gz: 1277e4a3d77f03f82d27a06777fa05bc1b5fb122
3
+ metadata.gz: dc459be343530c48011ba904ffd9c63471f1019d
4
+ data.tar.gz: b825c0d34229dd97637876a93aef82a607098ba4
5
5
  SHA512:
6
- metadata.gz: 4eee37ed2c9f653ed8ef651ff4c1e72625e8dbc480a75299752d0d236377ee2b69537f7e21b0a6ebfb278631c223d2e0cde07947b6bdf7b17736b3a7982a6792
7
- data.tar.gz: f3518b6a0546434f24f54fb57cad8a1ba73cbcc6fd6720ade4d25b3d529b85662261732f5f7b86f90e2d6bbd8f65f0d909286e8a0de06abe805d4af3dbe8c9e0
6
+ metadata.gz: 36075469a864e5175e3f9a5ab58115eeac91e9855fbbce69974d8c3a37ab26839f90aba0d2aad07e980f5dba4577673b6194e9984168dd4f15bc8bb8908e3192
7
+ data.tar.gz: 5595a51d3846421051df79a6b7033dbe6d82188099e4ed56f60a12bb0f5f79cc63c8a2d0a4be18f3e7faf45efd67a974c43bb3698be10cbac8d73339adf7c40f
data/.gitignore CHANGED
@@ -3,6 +3,7 @@
3
3
  .bundle
4
4
  .config
5
5
  .yardoc
6
+ .DS_Store
6
7
  Gemfile.lock
7
8
  InstalledFiles
8
9
  _yardoc
@@ -0,0 +1,20 @@
1
+ module AWS
2
+ module Record
3
+ module Attributes
4
+ class SerializedAttr < BaseAttr
5
+
6
+ # OVERRIDE
7
+ # https://github.com/aws/aws-sdk-ruby/blob/master/lib/aws/record/attributes.rb#L372
8
+ # Allow Time instead of just DateTime
9
+ def self.serialize datetime, options = {}
10
+ unless datetime.is_a?(DateTime) || datetime.is_a?(Time)
11
+ msg = "expected a DateTime value, got #{datetime.class}"
12
+ raise ArgumentError, msg
13
+ end
14
+ datetime.strftime('%Y-%m-%dT%H:%M:%S%Z')
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -11,16 +11,20 @@ module DynaModel
11
11
  extend Options
12
12
 
13
13
  # All the default options.
14
- option :logger, :default => defined?(Rails)
15
- option :read_provision, :default => 50
16
- option :write_provision, :default => 10
14
+ option :logger, default: defined?(Rails)
15
+ option :read_provision, default: 50
16
+ option :write_provision, default: 10
17
17
  # TODO - default adapter client based on config
18
18
  #option :namespace, :default => defined?(Rails) ? "#{Rails.application.class.parent_name}_#{Rails.env}" : ""
19
- option :endpoint, :default => 'dynamodb.us-west-2.amazonaws.com'
20
- option :port, :default => 443
21
- option :use_ssl, :default => true
22
- option :default_guid_delimiter, :default => ":"
23
- option :namespace, :default => ""
19
+ option :endpoint, default: 'dynamodb.us-west-2.amazonaws.com'
20
+ option :port, default: 443
21
+ option :use_ssl, default: true
22
+ option :default_guid_delimiter, default: ":"
23
+ option :namespace, default: ""
24
+
25
+ option :lock_extension_read_provision, default: 10
26
+ option :lock_extension_write_provision, default: 4
27
+ option :lock_extension_shard_name, default: "lock"
24
28
 
25
29
  # The default logger: either the Rails logger or just stdout.
26
30
  def default_logger
@@ -0,0 +1,125 @@
1
+ module DynaModel
2
+ module Extensions
3
+ class Lock
4
+
5
+ class LockNotAcquired < StandardError
6
+ end
7
+
8
+ HOST = `hostname`.strip
9
+
10
+ include DynaModel::Document
11
+
12
+ string_attr :lock_name
13
+ datetime_attr :locked_at
14
+ datetime_attr :expires_at
15
+ string_attr :locked_by
16
+
17
+ hash_key :lock_name
18
+
19
+ set_shard_name DynaModel::Config.lock_extension_shard_name
20
+
21
+ read_provision DynaModel::Config.lock_extension_read_provision
22
+ write_provision DynaModel::Config.lock_extension_write_provision
23
+
24
+ def self.locked_by
25
+ "#{HOST}:#{Process.pid}"
26
+ end
27
+
28
+ def self.lock(lock_name, options={}, &block)
29
+ lock_acquired = false
30
+ if lock_obj_acquired = self.acquire(lock_name, options)
31
+ lock_acquired = true
32
+ if block
33
+ begin
34
+ result = (block.arity == 1) ? block.call(lock_obj_acquired) : block.call
35
+ ensure
36
+ release(lock_name) if lock_acquired
37
+ end
38
+ end
39
+ result
40
+ end
41
+ end
42
+
43
+ def self.acquire(lock_name, options={})
44
+ options[:acquisition_timeout] ||= 15
45
+ options[:expires_in] ||= 10
46
+
47
+ retries = 0
48
+ begin
49
+ Timeout::timeout(options[:acquisition_timeout]) do
50
+ begin
51
+ locked_at = DateTime.now
52
+ expires_at = locked_at + options[:expires_in].seconds
53
+ lock_obj = self.new(
54
+ lock_name: lock_name,
55
+ locked_at: locked_at,
56
+ expires_at: expires_at,
57
+ locked_by: self.locked_by
58
+ )
59
+ if lock_obj.save(expected: {
60
+ :locked_by.null => "",
61
+ :expires_at.le => locked_at
62
+ }, conditional_operator: :or)
63
+ DynaModel::Config.logger.info "Acquired lock '#{lock_name}'"
64
+ lock_obj
65
+ else
66
+ raise "Error acquiring lock: #{lock_obj.errors.full_messages.to_sentence}"
67
+ end
68
+ rescue AWS::DynamoDB::Errors::ConditionalCheckFailedException
69
+ DynaModel::Config.logger.info "Lock condition failed for '#{lock_name}'. Retrying..."
70
+ sleep((2 ** retries) * 0.05)
71
+ retries += 1
72
+ retry
73
+ end
74
+ end
75
+ rescue Timeout::Error
76
+ raise LockNotAcquired, "Could not acquire lock after #{options[:acquisition_timeout]} seconds"
77
+ end
78
+ end
79
+
80
+ def self.release(lock_name, options={})
81
+ lock_obj = self.new(
82
+ lock_name: lock_name,
83
+ locked_at: nil,
84
+ expires_at: nil,
85
+ locked_by: nil
86
+ )
87
+
88
+ if lock_obj.save(expected: {
89
+ :locked_by.eq => self.locked_by
90
+ })
91
+ DynaModel::Config.logger.info "Released lock '#{lock_name}'"
92
+ true
93
+ else
94
+ raise "Error releasing lock: #{lock_obj.errors.full_messages.to_sentence}"
95
+ end
96
+ rescue AWS::DynamoDB::Errors::ConditionalCheckFailedException => e
97
+ DynaModel::Config.logger.info "Condition failed to release lock '#{lock_name}'"
98
+ end
99
+
100
+ def self.extend(lock_name, extension_time=5.seconds)
101
+ locked_at = DateTime.now
102
+ expires_at = locked_at + extension_time
103
+
104
+ lock_obj = self.new(
105
+ lock_name: lock_name,
106
+ locked_at: locked_at,
107
+ expires_at: expires_at,
108
+ locked_by: self.locked_by
109
+ )
110
+
111
+ if lock_obj.save(expected: {
112
+ :locked_by.eq => self.locked_by
113
+ })
114
+ DynaModel::Config.logger.info "Extended lock '#{lock_name}' for #{extension_time} seconds"
115
+ true
116
+ else
117
+ raise "Error extending lock: #{lock_obj.errors.full_messages.to_sentence}"
118
+ end
119
+ rescue AWS::DynamoDB::Errors::ConditionalCheckFailedException => e
120
+ DynaModel::Config.logger.info "Condition failed to extend lock '#{lock_name}'"
121
+ end
122
+
123
+ end
124
+ end
125
+ end
@@ -155,11 +155,11 @@ module DynaModel
155
155
  end
156
156
 
157
157
  if @schema_loaded_from_dynamo[:table][:provisioned_throughput][:read_capacity_units] != @table_schema[:provisioned_throughput][:read_capacity_units]
158
- Toy::Dynamo::Config.logger.error "read_capacity_units mismatch. Need to update table?"
158
+ DynaModel::Config.logger.error "read_capacity_units mismatch. Need to update table?"
159
159
  end
160
160
 
161
161
  if @schema_loaded_from_dynamo[:table][:provisioned_throughput][:write_capacity_units] != @table_schema[:provisioned_throughput][:write_capacity_units]
162
- Toy::Dynamo::Config.logger.error "write_capacity_units mismatch. Need to update table?"
162
+ DynaModel::Config.logger.error "write_capacity_units mismatch. Need to update table?"
163
163
  end
164
164
  end
165
165
 
@@ -513,6 +513,7 @@ module DynaModel
513
513
  attr_name, comparison_operator = attr_conditional.keys.first.split(".")
514
514
  raise ArgumentError, "Comparison operator must be one of (#{(COMPARISON_OPERATOR.keys - COMPARISON_OPERATOR_SCAN_ONLY).join(", ")})" unless COMPARISON_OPERATOR.keys.include?(comparison_operator.to_sym)
515
515
  attr_key = @model.attributes[attr_name]
516
+ attr_class = attr_key.class
516
517
  raise ArgumentError, "#{attr_name} not a valid attribute" unless attr_key
517
518
  attr_type = @model.attribute_type_indicator(attr_key)
518
519
  raise ArgumentError, "#{attr_name} key must be a Range if using the operator BETWEEN" if comparison_operator == "between" && !attr_conditional.values.first.is_a?(Range)
@@ -522,14 +523,14 @@ module DynaModel
522
523
 
523
524
  attribute_value_list = []
524
525
  if comparison_operator == "in"
525
- attr_conditional.values.first.each do |in_v|
526
- attribute_value_list << { attr_type => in_v.to_s }
526
+ attr_value.each do |in_v|
527
+ attribute_value_list << { attr_type => casted_attr_value(attr_class, in_v).to_s }
527
528
  end
528
529
  elsif comparison_operator == "between"
529
530
  attribute_value_list << { attr_type => attr_value.min.to_s }
530
531
  attribute_value_list << { attr_type => attr_value.max.to_s }
531
532
  else
532
- attribute_value_list = [{ attr_type => attr_value.to_s }]
533
+ attribute_value_list = [{ attr_type => casted_attr_value(attr_class, attr_value).to_s }]
533
534
  end
534
535
 
535
536
  attribute_comparison_hash = {
@@ -540,5 +541,11 @@ module DynaModel
540
541
  { attr_name => attribute_comparison_hash }
541
542
  end
542
543
 
544
+ def casted_attr_value(attr_class, val)
545
+ casted = attr_class.type_cast(val)
546
+ return nil if casted.nil?
547
+ attr_class.serialize(casted)
548
+ end
549
+
543
550
  end
544
551
  end
@@ -1,3 +1,3 @@
1
1
  module DynaModel
2
- VERSION = "0.0.8"
2
+ VERSION = "0.0.9"
3
3
  end
data/lib/dyna_model.rb CHANGED
@@ -14,9 +14,10 @@ require "dyna_model/table"
14
14
  require "dyna_model/query"
15
15
  require "dyna_model/response"
16
16
  require "dyna_model/validations"
17
+ require "dyna_model/document"
17
18
  require "dyna_model/extensions/symbol"
18
19
  require "dyna_model/extensions/s3_backup"
19
- require "dyna_model/document"
20
+ require "dyna_model/extensions/lock"
20
21
 
21
22
  module DynaModel
22
23
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dyna_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cary Dunn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-04-28 00:00:00.000000000 Z
11
+ date: 2014-04-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -139,10 +139,12 @@ files:
139
139
  - lib/dyna_model/adapters/carrierwave/dyna_model.rb
140
140
  - lib/dyna_model/adapters/elasticsearch/dyna_model_adapter.rb
141
141
  - lib/dyna_model/attributes.rb
142
+ - lib/dyna_model/aws/record/attributes/date_time_attr.rb
142
143
  - lib/dyna_model/aws/record/attributes/serialized_attr.rb
143
144
  - lib/dyna_model/config.rb
144
145
  - lib/dyna_model/config/options.rb
145
146
  - lib/dyna_model/document.rb
147
+ - lib/dyna_model/extensions/lock.rb
146
148
  - lib/dyna_model/extensions/s3_backup.rb
147
149
  - lib/dyna_model/extensions/symbol.rb
148
150
  - lib/dyna_model/persistence.rb