-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for native ETCD distributed locks (#122)
* implement ETCD locking * expand README.md * fix typos in README.md * add Connection#with_lock * Update to grpc 1.17.0 Grpc was being kept at 1.6.0, which does not support ruby 2.5.0. Since that important for us, update to 1.17.0 and solve issue with deadline in spec by using `#from_relative_time` provided by `GRPC::Core::TimeConsts` instead of our own implementation. Also provide rake file with task to download etcd and improve travis config to test more configurations. * Don't test lock in etcd v3.1.X * Use version from test instance * Disable 3.3.10 in travis (doesn't work) * Improve test coverage to make codecov happy * Don't test locks in 3.1.0 * add lease support to #lock * fix specs * fix doc comments * fix README.md locking examples
- Loading branch information
Showing
21 changed files
with
303 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,19 @@ | ||
language: ruby | ||
rvm: | ||
- 2.4.1 | ||
- 2.2 | ||
- 2.5.3 | ||
- 2.4.5 | ||
- 2.3.8 | ||
|
||
env: | ||
global: | ||
- ETCD_VERSION=v3.2.0 | ||
- ETCD_VERSION=v3.1.20 | ||
- ETCD_VERSION=v3.2.25 | ||
# v3.3.10 is not working for whatever reason (at least in travis, spec passes | ||
# locally for me) | ||
# - ETCD_VERSION=v3.3.10 | ||
|
||
install: | ||
- bundle install | ||
- wget https://github.com/coreos/etcd/releases/download/$ETCD_VERSION/etcd-$ETCD_VERSION-linux-amd64.tar.gz -O etcd.tar.gz --no-check-certificate | ||
- tar zxvf etcd.tar.gz | ||
- export PATH=$PATH:etcd-$ETCD_VERSION-linux-amd64 | ||
- bundle exec rake download-etcd | ||
- export PATH="$(dirname $(find /tmp -name 'etcd')):$PATH" | ||
|
||
script: bundle exec rspec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# frozen_string_literal: true | ||
|
||
ETCD_VERSION = ENV["ETCD_VERSION"] || "v3.2.0" | ||
ETCD_URL = "https://github.com/coreos/etcd/releases/download/#{ETCD_VERSION}/etcd-#{ETCD_VERSION}-linux-amd64.tar.gz" | ||
|
||
require "tmpdir" | ||
|
||
desc "Download etcd for it can be used in rspec" | ||
task :"download-etcd" do | ||
tmpdir = Dir.mktmpdir | ||
system("wget", ETCD_URL, "-O", "#{tmpdir}/etcd.tar.gz") || exit(1) | ||
system(*%W{tar -C #{tmpdir} -zxvf #{tmpdir}/etcd.tar.gz}) || exit(1) | ||
|
||
puts "Etcd downloaded and extracted. Add it to the path:" | ||
puts " export PATH=\"#{tmpdir}/etcd-#{ETCD_VERSION}-linux-amd64:$PATH\"" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
class Etcdv3 | ||
class Lock | ||
include GRPC::Core::TimeConsts | ||
|
||
def initialize(hostname, credentials, timeout, metadata = {}) | ||
@stub = V3lockpb::Lock::Stub.new(hostname, credentials) | ||
@timeout = timeout | ||
@metadata = metadata | ||
end | ||
|
||
def lock(name, lease_id, timeout: nil) | ||
request = V3lockpb::LockRequest.new(name: name, lease: lease_id) | ||
@stub.lock(request, deadline: deadline(timeout)) | ||
end | ||
|
||
def unlock(key, timeout: nil) | ||
request = V3lockpb::UnlockRequest.new(key: key) | ||
@stub.unlock(request, deadline: deadline(timeout)) | ||
end | ||
|
||
private | ||
|
||
def deadline(timeout) | ||
from_relative_time(timeout || @timeout) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
syntax = "proto3"; | ||
package v3lockpb; | ||
|
||
import "annotations.proto"; | ||
import "rpc.proto"; | ||
import "gogo.proto"; | ||
|
||
option (gogoproto.marshaler_all) = true; | ||
option (gogoproto.unmarshaler_all) = true; | ||
|
||
service Lock { | ||
// Lock acquires a distributed shared lock on a given named lock. | ||
rpc Lock(LockRequest) returns (LockResponse) { | ||
option (google.api.http) = { | ||
post: "/v3alpha/lock/lock" | ||
body: "*" | ||
}; | ||
} | ||
|
||
// Unlock takes a key returned by Lock and releases the hold on lock. | ||
rpc Unlock(UnlockRequest) returns (UnlockResponse) { | ||
option (google.api.http) = { | ||
post: "/v3alpha/lock/unlock" | ||
body: "*" | ||
}; | ||
} | ||
} | ||
|
||
message LockRequest { | ||
// name is the identifier for the distributed shared lock to be acquired. | ||
bytes name = 1; | ||
// lease is the ID of the lease that will be attached to ownership of the | ||
// lock. If the lease expires or is revoked and currently holds the lock, | ||
// the lock is automatically released. Calls to Lock with the same lease will | ||
// be treated as a single acquisition; locking twice with the same lease is a | ||
// no-op. | ||
int64 lease = 2; | ||
} | ||
|
||
message LockResponse { | ||
etcdserverpb.ResponseHeader header = 1; | ||
// key is a key that will exist on etcd for the duration that the Lock caller | ||
// owns the lock. Users should not modify this key or the lock may exhibit | ||
// undefined behavior. | ||
bytes key = 2; | ||
} | ||
|
||
message UnlockRequest { | ||
// key is the lock ownership key granted by Lock. | ||
bytes key = 1; | ||
} | ||
|
||
message UnlockResponse { | ||
etcdserverpb.ResponseHeader header = 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
require 'spec_helper' | ||
|
||
# Locking is not implemented in etcd v3.1.X | ||
unless $instance.version < Gem::Version.new("3.2.0") | ||
describe Etcdv3::Lock do | ||
let(:stub) { local_stub(Etcdv3::Lock, 1) } | ||
let(:lease_stub) { local_stub(Etcdv3::Lease, 1) } | ||
|
||
it_should_behave_like "a method with a GRPC timeout", described_class, :unlock, :unlock, 'foo' | ||
#it_should_behave_like "a method with a GRPC timeout", described_class, :lock, :lock, 'foo' | ||
|
||
describe '#lock' do | ||
let(:lease_id) { lease_stub.lease_grant(10)['ID'] } | ||
subject { stub.lock('foo', lease_id) } | ||
it { is_expected.to be_an_instance_of(V3lockpb::LockResponse) } | ||
end | ||
|
||
describe '#unlock' do | ||
subject { stub.unlock('foo') } | ||
it { is_expected.to be_an_instance_of(V3lockpb::UnlockResponse) } | ||
end | ||
end | ||
end |
Oops, something went wrong.