Class: Tina4::CacheBackends::MongoBackend

Inherits:
BaseBackend
  • Object
show all
Defined in:
lib/tina4/cache_backends/mongo_backend.rb

Overview

MongoDB backend backed by a TTL collection (parity with Python _MongoBackend). Requires the ‘mongo` gem — reuses the same connection style as the Mongo session handler. The cache lives in collection tina4_cache with a TTL index on expires_at. The database name is taken from the URL path (mongodb://host:27017/<db>) or defaults to tina4_cache.

Instance Method Summary collapse

Constructor Details

#initialize(url: "mongodb://localhost:27017", max_entries: 1000) ⇒ MongoBackend

Returns a new instance of MongoBackend.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/tina4/cache_backends/mongo_backend.rb', line 15

def initialize(url: "mongodb://localhost:27017", max_entries: 1000)
  @max_entries = max_entries
  @hits = 0
  @misses = 0
  @coll = nil
  begin
    require "mongo"
    Mongo::Logger.logger.level = Logger::FATAL if defined?(Mongo::Logger)
    db_name = database_from_url(url)
    client_opts = { server_selection_timeout: 5, database: db_name }
    # Credentials from env when not embedded in the URL (parity with DB layer).
    unless url.include?("@")
      mu = env_nonempty("TINA4_CACHE_USERNAME")
      mp = env_nonempty("TINA4_CACHE_PASSWORD")
      client_opts[:user] = mu if mu
      client_opts[:password] = mp if mp
    end
    client = Mongo::Client.new(url, **client_opts)
    @coll = client[:tina4_cache]
    @coll.indexes.create_one({ expires_at: 1 }, expire_after: 0)
    client.database.command(ping: 1)
  rescue LoadError, StandardError
    @coll = nil
  end
end

Instance Method Details

#available?Boolean

Returns:

  • (Boolean)


41
42
43
# File 'lib/tina4/cache_backends/mongo_backend.rb', line 41

def available?
  !@coll.nil?
end

#clearObject



91
92
93
94
95
96
97
98
99
100
# File 'lib/tina4/cache_backends/mongo_backend.rb', line 91

def clear
  @hits = 0
  @misses = 0
  return if @coll.nil?

  begin
    @coll.delete_many({})
  rescue StandardError
  end
end

#delete(key) ⇒ Object



81
82
83
84
85
86
87
88
89
# File 'lib/tina4/cache_backends/mongo_backend.rb', line 81

def delete(key)
  return false if @coll.nil?

  begin
    @coll.delete_one(_id: key).deleted_count > 0
  rescue StandardError
    false
  end
end

#get(key) ⇒ Object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/tina4/cache_backends/mongo_backend.rb', line 45

def get(key)
  if @coll.nil?
    @misses += 1
    return nil
  end
  begin
    doc = @coll.find(_id: key).first
    unless doc
      @misses += 1
      return nil
    end
    exp = doc["expires_at"]
    if exp && exp < Time.now.utc
      @coll.delete_one(_id: key)
      @misses += 1
      return nil
    end
    @hits += 1
    JSON.parse(doc["value"])
  rescue StandardError
    @misses += 1
    nil
  end
end

#nameObject



113
114
115
# File 'lib/tina4/cache_backends/mongo_backend.rb', line 113

def name
  "mongodb"
end

#set(key, value, ttl) ⇒ Object



70
71
72
73
74
75
76
77
78
79
# File 'lib/tina4/cache_backends/mongo_backend.rb', line 70

def set(key, value, ttl)
  return if @coll.nil?

  begin
    doc = { _id: key, value: JSON.generate(value) }
    doc[:expires_at] = Time.now.utc + ttl if ttl > 0
    @coll.replace_one({ _id: key }, doc, upsert: true)
  rescue StandardError
  end
end

#statsObject



102
103
104
105
106
107
108
109
110
111
# File 'lib/tina4/cache_backends/mongo_backend.rb', line 102

def stats
  size = 0
  unless @coll.nil?
    begin
      size = @coll.count_documents({})
    rescue StandardError
    end
  end
  { hits: @hits, misses: @misses, size: size, backend: "mongodb" }
end