legion-cache 0.2.0 → 1.2.0

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.
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=.