class Terrafying::DynamoDb::NamedLock

Public Class Methods

new(table_name, name) click to toggle source
# File lib/terrafying/dynamodb/named_lock.rb, line 9
def initialize(table_name, name)
  @table_name = table_name
  @name = name
  @client = Terrafying::DynamoDb.client
end

Public Instance Methods

acquire() click to toggle source
# File lib/terrafying/dynamodb/named_lock.rb, line 38
def acquire
  @client.ensure_table(table) do
    lock_id = SecureRandom.uuid
    @client.update_item(acquire_request(lock_id))
    return lock_id
  rescue ::Aws::DynamoDB::Errors::ConditionalCheckFailedException
    raise "Unable to acquire lock: #{status.inspect}" # TODO
  end
end
release(lock_id) click to toggle source
# File lib/terrafying/dynamodb/named_lock.rb, line 60
def release(lock_id)
  @client.ensure_table(table) do
    @client.delete_item(
      table_name: @table_name,
      key: {
        'name' => @name
      },
      return_values: 'NONE',
      condition_expression: 'lock_id = :lock_id',
      expression_attribute_values: {
        ':lock_id' => lock_id
      }
    )
    nil
  rescue ::Aws::DynamoDB::Errors::ConditionalCheckFailedException
    raise "Unable to release lock: #{status.inspect}" # TODO
  end
end
status() click to toggle source
# File lib/terrafying/dynamodb/named_lock.rb, line 15
def status
  @client.ensure_table(table) do
    resp = @client.get_item(
      table_name: @table_name,
      key: {
        'name' => @name
      },
      consistent_read: true
    )
    if resp.item
      return {
        status: :locked,
        locked_at: resp.item['locked_at'],
        metadata: resp.item['metadata']
      }
    else
      return {
        status: :unlocked
      }
    end
  end
end
steal() click to toggle source
# File lib/terrafying/dynamodb/named_lock.rb, line 48
def steal
  @client.ensure_table(table) do
    lock_id = SecureRandom.uuid
    req = acquire_request(lock_id)
    req.delete(:condition_expression)
    @client.update_item(req)
    return lock_id
  rescue ::Aws::DynamoDB::Errors::ConditionalCheckFailedException
    raise "Unable to steal lock: #{status.inspect}" # TODO
  end
end

Private Instance Methods

acquire_request(lock_id) click to toggle source
# File lib/terrafying/dynamodb/named_lock.rb, line 81
def acquire_request(lock_id)
  {
    table_name: @table_name,
    key: {
      'name' => @name
    },
    return_values: 'NONE',
    update_expression: 'SET lock_id = :lock_id, locked_at = :locked_at, metadata = :metadata',
    condition_expression: 'attribute_not_exists(lock_id)',
    expression_attribute_values: {
      ':lock_id' => lock_id,
      ':locked_at' => Time.now.to_s,
      ':metadata' => {
        'owner' => "#{`git config user.name`.chomp} (#{`git config user.email`.chomp})"
      }
    }
  }
end
table() click to toggle source
# File lib/terrafying/dynamodb/named_lock.rb, line 100
def table
  {
    table_name: @table_name,
    attribute_definitions: [
      {
        attribute_name: 'name',
        attribute_type: 'S'
      }
    ],
    key_schema: [
      {
        attribute_name: 'name',
        key_type: 'HASH'
      }
    ],
    provisioned_throughput: {
      read_capacity_units: 1,
      write_capacity_units: 1
    }
  }
end