legion-cache 0.2.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/NOTICE.txt ADDED
@@ -0,0 +1,9 @@
1
+ Legion::Cache(legion-cache)
2
+ Copyright 2021 Optum
3
+
4
+ Project Description:
5
+ ====================
6
+ A Wrapper class for the LegionIO framework to interface with both Memcached and Redis for caching purposes
7
+
8
+ Author(s):
9
+ Esity
data/README.md CHANGED
@@ -1,38 +1,59 @@
1
- # Legion::Cache
1
+ Legion::Cache
2
+ =====
2
3
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/legion/cache`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+ Legion::Cache is a wrapper class to handle requests to the caching tier. It supports both memcached and redis
4
5
 
5
- ## Installation
6
+ Supported Ruby versions and implementations
7
+ ------------------------------------------------
6
8
 
7
- Add this line to your application's Gemfile:
9
+ Legion::Json should work identically on:
8
10
 
9
- ```ruby
10
- gem 'legion-cache'
11
- ```
12
-
13
- And then execute:
14
-
15
- $ bundle install
16
-
17
- Or install it yourself as:
18
-
19
- $ gem install legion-cache
11
+ * JRuby 9.2+
12
+ * Ruby 2.4+
20
13
 
21
- ## Usage
22
14
 
15
+ Installation and Usage
16
+ ------------------------
23
17
 
18
+ You can verify your installation using this piece of code:
24
19
 
25
- ## Development
26
-
27
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
20
+ ```bash
21
+ gem install legion-cache
22
+ ```
28
23
 
29
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
24
+ ```ruby
25
+ require 'legion/cache'
30
26
 
31
- ## Contributing
27
+ Legion::Cache.setup
28
+ Legion::Cache.connected? # => true
29
+ Legion::Cache.set('foobar', 'testing', ttl: 10)
30
+ Legion::Cache.get('foobar') # => 'testing'
31
+ sleep(11)
32
+ Legion::Cache.get('foobar') # => nil
32
33
 
33
- Bug reports and pull requests are welcome on GitHub at https://bitbucket.org/legion-io/legion-cache/issues
34
+ ```
34
35
 
36
+ Settings
37
+ ----------
38
+
39
+ ```json
40
+ {
41
+ "driver": "dalli",
42
+ "servers": [
43
+ "127.0.0.1:11211"
44
+ ],
45
+ "connected": false,
46
+ "enabled": true,
47
+ "namespace": "legion",
48
+ "compress": false,
49
+ "cache_nils": false,
50
+ "pool_size": 10,
51
+ "timeout": 10,
52
+ "expires_in": 0
53
+ }
54
+ ```
35
55
 
36
- ## License
56
+ Authors
57
+ ----------
37
58
 
38
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
59
+ * [Matthew Iverson](https://github.com/Esity) - current maintainer
data/SECURITY.md ADDED
@@ -0,0 +1,9 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+ | Version | Supported |
5
+ | ------- | ------------------ |
6
+ | 1.x.x | :white_check_mark: |
7
+
8
+ ## Reporting a Vulnerability
9
+ To be added
data/attribution.txt ADDED
@@ -0,0 +1 @@
1
+ Add attributions here.
data/legion-cache.gemspec CHANGED
@@ -3,40 +3,32 @@
3
3
  require_relative 'lib/legion/cache/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.name = 'legion-cache'
6
+ spec.name = 'legion-cache'
7
7
  spec.version = Legion::Cache::VERSION
8
8
  spec.authors = ['Esity']
9
- spec.email = ['matthewdiverson@gmail.com']
9
+ spec.email = %w[matthewdiverson@gmail.com ruby@optum.com]
10
10
 
11
- spec.summary = 'Legion::Cache integration'
12
- spec.description = 'Used to connect Legion with a cache service like memcached'
13
- spec.homepage = 'https://bitbucket.org/legion-io/legion-cache'
14
- spec.license = 'MIT'
15
- spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
16
-
17
- spec.metadata['homepage_uri'] = spec.homepage
18
- spec.metadata['source_code_uri'] = 'https://bitbucket.org/legion-io/legion-cache/src'
19
- spec.metadata['changelog_uri'] = 'https://bitbucket.org/legion-io/legion-cache/src/master/CHANGELOG.md'
20
- spec.metadata['wiki_uri'] = 'https://bitbucket.org/legion-io/legion-cache/wiki'
21
- spec.metadata['bug_tracker_uri'] = 'https://bitbucket.org/legion-io/legion-cache/issues'
22
-
23
- spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
- end
26
- spec.bindir = 'exe'
27
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
11
+ spec.summary = 'Wraps both the redis and dalli gems to make a consistent interface for accessing cached objects'
12
+ spec.description = 'A Wrapper class for the LegionIO framework to interface with both Memcached and Redis for caching purposes'
13
+ spec.homepage = 'https://github.com/Optum/legion-cache'
14
+ spec.license = 'Apache-2.0'
28
15
  spec.require_paths = ['lib']
16
+ spec.required_ruby_version = '>= 2.4'
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.test_files = spec.files.select { |p| p =~ %r{^test/.*_test.rb} }
19
+ spec.extra_rdoc_files = %w[README.md LICENSE CHANGELOG.md]
20
+ spec.metadata = {
21
+ 'bug_tracker_uri' => 'https://github.com/Optum/legion-cache/issues',
22
+ 'changelog_uri' => 'https://github.com/Optum/legion-cache/src/main/CHANGELOG.md',
23
+ 'documentation_uri' => 'https://github.com/Optum/legion-cache',
24
+ 'homepage_uri' => 'https://github.com/Optum/LegionIO',
25
+ 'source_code_uri' => 'https://github.com/Optum/legion-cache',
26
+ 'wiki_uri' => 'https://github.com/Optum/legion-cache/wiki'
27
+ }
29
28
 
30
- spec.add_development_dependency 'bundler'
31
- spec.add_development_dependency 'legion-logging'
32
- spec.add_development_dependency 'legion-settings'
33
- spec.add_development_dependency 'rake'
34
- spec.add_development_dependency 'rspec'
35
- spec.add_development_dependency 'rspec_junit_formatter'
36
- spec.add_development_dependency 'rubocop'
37
- spec.add_development_dependency 'simplecov'
38
-
39
- spec.add_dependency 'connection_pool'
40
- spec.add_dependency 'dalli'
41
- spec.add_dependency 'redis'
29
+ spec.add_dependency 'connection_pool', '>= 2.2.3'
30
+ spec.add_dependency 'dalli', '>= 2.7'
31
+ spec.add_dependency 'legion-logging'
32
+ spec.add_dependency 'legion-settings'
33
+ spec.add_dependency 'redis', '>= 4.2'
42
34
  end
data/lib/legion/cache.rb CHANGED
@@ -1,19 +1,25 @@
1
- require_relative 'cache/version'
2
- require_relative 'cache/settings'
1
+ require 'legion/cache/version'
2
+ require 'legion/cache/settings'
3
3
 
4
- require_relative 'cache/memcached'
5
- require_relative 'cache/redis'
4
+ require 'legion/cache/memcached'
5
+ require 'legion/cache/redis'
6
6
 
7
7
  module Legion
8
8
  module Cache
9
9
  class << self
10
- attr_reader :client
11
- include Legion::Cache::Memcached if Legion::Settings[:cache][:driver] == 'dalli'
12
- include Legion::Cache::Redis if Legion::Settings[:cache][:driver] == 'redis'
10
+ if Legion::Settings[:cache][:driver] == 'redis'
11
+ include Legion::Cache::Redis
12
+ else
13
+ include Legion::Cache::Memcached
14
+ end
15
+
16
+ def setup(**opts)
17
+ return Legion::Settings[:cache][:connected] = true if connected?
18
+
19
+ return unless client(**Legion::Settings[:cache], **opts)
13
20
 
14
- def setup
15
- connect
16
- Legion::Logging.info 'Legion::Cache connected and enabled'
21
+ @connected = true
22
+ Legion::Settings[:cache][:connected] = true
17
23
  end
18
24
 
19
25
  def shutdown
@@ -1,47 +1,45 @@
1
1
  require 'dalli'
2
+ require 'legion/cache/pool'
2
3
 
3
4
  module Legion
4
5
  module Cache
5
6
  module Memcached
6
- def connect
7
- Legion::Logging.debug 'Using Memcached module for Legion::Cache'
8
- options = { compress: true,
9
- serializer: Legion::JSON,
10
- failover: Legion::Settings[:cache][:failover],
11
- namespace: Legion::Settings[:cache][:namespace], foo: 'test' }
12
- Dalli.logger = Legion::Logging
13
- @client = Dalli::Client.new(Legion::Settings[:cache][:servers], options)
14
- Legion::Logging.debug "Legion::Cache successfully connected to #{Legion::Settings[:cache][:servers]}"
15
- Legion::Settings[:cache][:connected] = true
16
- end
7
+ include Legion::Cache::Pool
8
+ extend self
17
9
 
18
- def close
19
- @client.close
20
- end
10
+ def client(servers: Legion::Settings[:cache][:servers], **opts)
11
+ return @client unless @client.nil?
12
+
13
+ @pool_size = opts.key?(:pool_size) ? opts[:pool_size] : Legion::Settings[:cache][:pool_size] || 10
14
+ @timeout = opts.key?(:timeout) ? opts[:timeout] : Legion::Settings[:cache][:timeout] || 5
15
+
16
+ Dalli.logger = Legion::Logging
17
+ @client = ConnectionPool.new(size: pool_size, timeout: timeout) do
18
+ Dalli::Client.new(servers, Legion::Settings[:cache].merge(opts))
19
+ end
21
20
 
22
- def restart
23
- close
24
- connect
21
+ @connected = true
22
+ @client
25
23
  end
26
24
 
27
25
  def get(key)
28
- @client.get(key)
26
+ client.with { |conn| conn.get(key) }
29
27
  end
30
28
 
31
29
  def fetch(key, ttl = nil)
32
- @client.fetch(key, ttl)
30
+ client.with { |conn| conn.fetch(key, ttl) }
33
31
  end
34
32
 
35
33
  def set(key, value, ttl = 180)
36
- @client.set(key, value, ttl)
34
+ client.with { |conn| conn.set(key, value, ttl).positive? }
37
35
  end
38
36
 
39
37
  def delete(key)
40
- @client.delete(key)
38
+ client.with { |conn| conn.delete(key) == true }
41
39
  end
42
40
 
43
41
  def flush(delay = 0)
44
- @client.flush(delay)
42
+ client.with { |conn| conn.flush(delay).first }
45
43
  end
46
44
  end
47
45
  end
@@ -0,0 +1,43 @@
1
+ require 'connection_pool'
2
+
3
+ module Legion
4
+ module Cache
5
+ module Pool
6
+ def connected?
7
+ @connected ||= false
8
+ end
9
+
10
+ def size
11
+ client.size
12
+ end
13
+
14
+ def timeout
15
+ @timeout ||= Legion::Settings[:cache][:timeout] || 5
16
+ end
17
+
18
+ def pool_size
19
+ @pool_size ||= Legion::Settings[:cache][:pool_size] || 10
20
+ end
21
+
22
+ def available
23
+ client.available
24
+ end
25
+
26
+ def close
27
+ client.shutdown(&:close)
28
+ @client = nil
29
+ @connected = false
30
+ end
31
+
32
+ def restart(**opts)
33
+ close
34
+ @client = nil
35
+ client_hash = opts
36
+ client_hash[:pool_size] = opts[:pool_size] if opts.key? :pool_size
37
+ client_hash[:timeout] = opts[:timeout] if opts.key? :timeout
38
+ client(**client_hash)
39
+ @connected = true
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,35 +1,42 @@
1
1
  require 'redis'
2
+ require 'legion/cache/pool'
2
3
 
3
4
  module Legion
4
5
  module Cache
5
6
  module Redis
6
- def connect
7
- @client = Redis.new
8
- end
7
+ include Legion::Cache::Pool
8
+ extend self
9
9
 
10
- def close
11
- @client.close
12
- end
10
+ def client(pool_size: 20, timeout: 5, **)
11
+ return @client unless @client.nil?
12
+
13
+ @pool_size = pool_size
14
+ @timeout = timeout
13
15
 
14
- def restart
15
- close
16
- connect
16
+ @client = ConnectionPool.new(size: pool_size, timeout: timeout) do
17
+ ::Redis.new
18
+ end
19
+ @connected = true
20
+ @client
17
21
  end
18
22
 
19
23
  def get(key)
20
- @client[key]
24
+ client.with { |conn| conn.get(key) }
21
25
  end
26
+ alias fetch get
22
27
 
23
- def set(key, value)
24
- @client[key] = value
28
+ def set(key, value, ttl: nil)
29
+ args = {}
30
+ args[:ex] = ttl unless ttl.nil?
31
+ client.with { |conn| conn.set(key, value, **args) == 'OK' }
25
32
  end
26
33
 
27
34
  def delete(key)
28
- @client.del key
35
+ client.with { |conn| conn.del(key) == 1 }
29
36
  end
30
37
 
31
38
  def flush
32
- @client.flushdb
39
+ client.with { |conn| conn.flushdb == 'OK' }
33
40
  end
34
41
  end
35
42
  end
@@ -1,28 +1,37 @@
1
+ begin
2
+ require 'legion/settings'
3
+ rescue StandardError
4
+ # empty block
5
+ end
6
+
1
7
  module Legion
2
8
  module Cache
3
9
  module Settings
10
+ Legion::Settings.merge_settings(:cache, default) if Legion::Settings.method_defined? :merge_settings
4
11
  def self.default
5
12
  {
6
- driver: 'dalli',
7
- servers: ['127.0.0.1:11211'],
8
- connected: false,
9
- enabled: true,
10
- namespace: 'legion',
11
- compress: false,
12
- failover: true,
13
+ driver: driver,
14
+ servers: ['127.0.0.1:11211'],
15
+ connected: false,
16
+ enabled: true,
17
+ namespace: 'legion',
18
+ compress: false,
19
+ failover: true,
13
20
  threadsafe: true,
14
21
  expires_in: 0,
15
22
  cache_nils: false,
16
- pool_size: 1,
23
+ pool_size: 10,
24
+ timeout: 5,
17
25
  serializer: Legion::JSON
18
26
  }
19
27
  end
20
28
 
21
- def self.driver
22
- if Gem::Specification.find_by_name('dalli')
23
- 'dalli'
24
- elsif Gem::Specification.find_by_name('redis')
25
- 'redis'
29
+ def self.driver(prefer = 'dalli')
30
+ secondary = prefer == 'dalli' ? 'redis' : 'dalli'
31
+ if Gem::Specification.find_all_by_name(prefer).count.positive?
32
+ prefer
33
+ elsif Gem::Specification.find_all_by_name(secondary).count.positive?
34
+ secondary
26
35
  else
27
36
  raise NameError('Legion::Cache.driver is nil')
28
37
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Legion
4
4
  module Cache
5
- VERSION = '0.2.0'
5
+ VERSION = '1.2.0'
6
6
  end
7
7
  end
@@ -0,0 +1,13 @@
1
+ sonar.projectKey=legion-io_legion-cache
2
+ sonar.organization=legion-io
3
+ sonar.projectName=Legion::Cache
4
+ sonar.sources=.
5
+ sonar.exclusions=vendor/**
6
+ sonar.coverage.exclusions=spec/**
7
+ sonar.cpd.exclusions=spec/**
8
+ sonar.ruby.coverage.reportPath=coverage/.resultset.json
9
+ sonar.ruby.file.suffixes=rb,ruby
10
+ sonar.ruby.coverage.framework=RSpec
11
+ sonar.ruby.rubocopConfig=.rubocop.yml
12
+ sonar.ruby.rubocop.reportPath=rubocop-result.json
13
+ sonar.ruby.rubocop.filePath=.