how many octets are read from the cache? - ruby-on-rails

I'm trying to do a simple benchmark to know how many octets are read from the cache in each page of my Rails site. I'm talking about the data retrieve from Rails.cache.
I would like to display something like 123Ko/145Ko at the bottom of my pages.
Does a gem exist to perform this task or perhaps is there something included in the ruby standard library?

One option is to subclass the store you're using and extend the protected read_entry method declared in ActiveSupport::Cache::Store, which FileStore and the other caches themselves subclass.
FileStoreWithReadTracking < ActiveSupport::Cache::FileStore
def start_page
#octets_read = 0
end
def octets_read
#octets_read
end
protected
def read_entry(key, options)
entry = super(key, options)
#octets_read += entry.size if entry
entry
end
end
When starting a page, you can call start_page to zero out the octet count. Since read_entry is a low-level method used every time the cache tries to perform a read, you can intercept any data read and get its size before returning it. You might have to convert size to octets.
To set this as your custom cache store, add config.cache_store = FileStoreWithReadTracking.new('/path/to/file/store') to your environment. I think you can subclass all the stores this way.

Related

is it possible to specify a cache with fragment caching or determine cache hit / miss ratio for a specific call

We have a Rails 4.2 app and are currently using a shared cache across several apps. Our memcached miss rate is pretty high (like 85% hits and 15% misses) but this is complicated by the fact that multiple apps are sharing the same memcached instance. So we might be getting a high miss rate for a couple of critical cache processes (our DataDog data would support this).
Is it possible to specify a cache store on a fragement cache call like:
cache(order, OrderCache) do
# whatever
end
I think this is possible with object caching by doing something like:
OrderCache = ActiveSupport::Cache::MemCacheStore.new
Would there be other ways to untangle the hit / miss ratio of specific cache actions?
Maybe it's a complicated idea but I think you can make your own cache store wrapper that decides which cache store to use if I understand your question correctly.
When calling the cache method, it eventually calls read_fragment and write_fragment on your controller https://apidock.com/rails/AbstractController/Caching/Fragments/read_fragment and those methods call cache_store.read and cache_store.write.
Then you could have a custom cache store class with custom read and write method that, depending on an option, delegates the read and write to real cache stores.
class MyCacheStore < ...
def initialize
#my_catchall_store = ActiveSupport::Cache::MemCacheStore.new
#my_order_store = ActiveSupport::Cache::MemCacheStore.new
end
def read(key, options)
case options[:store]
when :order_store then #my_order_store.read(key, options)
else
#my_catchall_store.read(key, options)
end
end
# similar for .write
Then you use it like...
cache(:order, store: :order_store) do
# some code
end
cache(:something_else) do
# some code
end
I'm not sure if that's what you are asking sorry.

Rails Memoization of Helper method

I have a helper method that does expensive calculations and returns a Hash, and this Hash is constant during my entire application lifespan (meaning it can only change after a re-deploy) and it also doesn't take any arguments.
For performance, I wish I could 'cache' the resulting Hash.
I don't want to use Rails cache for this, since I want to avoid the extra trip to memcached and I don't want the overhead of de-serializing the string into a hash.
My first idea was to assign the resulting hash to a Constant and calling .freeze on it. But the helper is an instance method, the constant lives on the class, and I had to do this ultra hacky solution:
module FooHelper
def expensive_calculation_method
resulting_hash
end
EXPENSIVE_CALCULATION_CONSTANT = Class.new.extend(self).expensive_calculation_method.freeze
This is due to the helper method being an instance method, the helper being a Module (which leads to the fake Class extend so I can call the instance method) and I also must declare the constant AFTER the instance method (if I declare it right after module FooHelper, I get an undefined method 'expensive_calculation_method'.
The second idea was to use memoization, but at least for Rails Controllers memoization is the persistance of a variable over the lifecycle of a single request, so it's only valuable if you reuse a variable many times from within a single request, which is not my case, but at the same time Helpers are modules, not Classes to be instanciated, and by this point I don't know what to do.
How would I cache that Hash, or memoize it in a way that persists over requests?
Per your comments, this will only change at application boot, so placing it in an initializer would do the trick.
# config/initializers/expensive_thing.rb
$EXENSIVE_THING_GLOBAL = expensive_calculation
# or
EXPENSIVE_THING_CONSTANT = expensive_calculation
# or
Rails.application.config.expensive_thing = expensive_calcualatioin
If you want to cache the result of some painful operation at launch time:
module MyExpensiveOperation
COMPUTED_RESULT = OtherModule.expensive_operation
def self.cached
COMPUTED_RESULT
end
end
Just make sure that module's loaded somehow or it won't initiate. You can always force-require that module if necessary in environment.rb or as a config/initializer type file.
If you want to lazy load the basic principle is the same:
module MyExpensiveOperation
def self.cached
return #cached if (defined?(#cached))
#cached = OtherModule.expensive_operation
end
end
That will handle operations that, for whatever reason, return nil or false. It will run once, and once only, unless you have multiple threads triggering it at the same time. If that's the case there's ways of making your module concurrency aware with automatic locks.

Best practice for a big array manipulation with values that never change and will be used in more than one view

What would be the best and more efficient way in Rails if I want to use a hash of about 300-500 integers (but it will never be modified) and use it in more than one view in the application?
Should I save the data in the database?, create the hash in each action that is used? (this is what I do now, but the code looks ugly and inefficient), or is there another option?
Why don't you put it in a constant? You said it will never change, so it fits either configuration or constant.
Using the cache has the downside that it can be dropped out of cache, triggering a reload, which seems quite useless in this case.
The overhead of having it always in memory is none, 500 integers are 4KB or something like that at most, you are safe.
You can write the hash manually or load a YAML file (or whatever) if you prefer, your choice.
My suggestion is create a file app/models/whatever.rb and:
module Whatever
MY_HASH = {
1 => 241
}.freeze
end
This will be preloaded by rails on startup (in production) and kept in memory all the time.
You can access those valus in view with Whatever::MY_HASH[1], or you can write a wrapper method like
module Whatever
MY_HASH = {
1 => 241
}.freeze
def self.get(id)
MY_HASH.fetch(id)
end
end
And use that Whatever.get(1)
If the data will never be changed, why not just calculate the values before hand and write them directly into the view?
Another option would be to put the values into a singleton and cache them there.
require 'singleton'
class MyHashValues
include Singleton
def initialize
#
#results = calculation
end
def result_key_1
#results[:result_key_1]
end
def calculation
Hash.new
end
end
MyHashValues.instance.result_key_1
Cache it, it'll do exactly what you want and it's a standard Rails component. If you're not caching yet, check out the Rails docs on caching. If you use the memory store, your data will essentially be in RAM.
You will then be able to do this sort of thing
# The block contains the value to cache, if there's a miss
# Setting the value is done initially and after the cache
# expires or is cleared.
# put this in application controller and make it a helper method
def integer_hash
cache.fetch('integer_hash') { ... }
end
helper_method :integer_hash

Permanent variable in Rails

Lets say that on top of my Rails app there is a bar with piece of text displayed - latest hot deal, scheduled downtime notfication, something like that. It's a single, on of a kind information that needs to be accessed on basically every request, and may be updated from time to time. What is the best way to achieve this?
What I'd like to do is some kind of permanent global variable (accessible from controllers).
It will be updated very rarely, so there's no problem if for some time after update there will be an inconsistency between workers.
On the other hand, it should be persistent in case of server fault (periodic backup is enough).
It will be accessed really often, so it should be as fast as possible - preferably stay in memory.
Also, it's only one of a kind, so I'd really prefer not to bloat the app with a dedicated database model.
Something like that is damn easy in Node.js for example, but I couldn't find a single way to achieve this in Rails. What shall I do?
EDIT
Thanks for the answers so far, but while they're inspiring, I think that I should stress out one key functionality that they're all missing. The variable should be editable inside the app and persistent. While it's possible to edit your variables, in case of server restart I'm back to the default - which is bad.
It really depends on what you are looking for. You could do something very simply by putting it in your application_controller.rb
class ApplicationController < ActionController::Base
def system_message
"Come buy our amazing .99 iphone chocolate bar apps, with 100% more gamification!"
end
end
That function (and string) is then accessible from any controller in your application. You could also specify something in the after_initialize block in your application.rb file.
config.after_initialize do
::MYTEXT = "MY SUPER AMAZING TEXT"
end
You could also create your own file under the initializers directory, which is preloaded in rails.
so siteAnnounce.rb
MYANNOUNCEMENT = "NOW LISTEN TO ME!"
You may also want to check out this Railscast video about site wide announcements
I would store it in the database and let caching take care of it.
I feel that global variables are fine, when appropriate, for code that needs to share that common value in many places but that is the code, not the the user view.
This is clearly true in this case as the OP has bolded 'editable by the app'. So I would have a view that lets the users enter it, it gets stored in a db table and then recalled as needed (as cached once used once).
Well I had faced a similar problem.
My problem was I needed a global variable in all the levels (MVC).
We went to use Memcache to store the variable.
May be you can go for a similar solution.
And as an added bonus you can change it throughout the program.
You could declare it as a constant in an initializer:
config/initialzers/foo.rb:
MYVARIABLE = 'some string'
Accessible from anywhere in your application as MYVARIABLE
Ok, so here's what I did. Instead of just putting the value to an initializer, I've made there a simple class that handles it. The variable itself is stored in a predefined file. Besides of reading the file upon the initialization, the class updates file when the value is changed, and also re-read the file periodically to maintain consistency across workers. I've also put there some basic JSON handling and backup functionality to make life easier.
For anyone interested, here's the important code:
class Pomegranate
def initialize
#delay = 30.minutes
#path = "db/pomegranate.json"
#valid = Time.now - 1
validate
end
def get(*p)
validate
p.inject(#data) {|object,key| object[key] if object}
end
def set(*p, q, v)
hash = p.inject(#data) {|object,key| object[key]||={}}
hash[q] = v
end
def save
#valid = Time.now + #delay
File.open(#path,"w") {|f| f.write(#data.to_json)}
end
private
def validate
if #valid < Time.now
#data = ActiveSupport::JSON.decode(File.read(#path)) rescue {}
#valid = Time.now + #delay
#valid = Time.now - 1 if #data.empty?
end
end
end
$pom = Pomegranate.new
Source:
Where to put Global variables in Rails 3
Try putting it in your applicaton.rb like this:
module MyAppName
class Application < Rails::Application
YOUR_GLOBAL_VAR = "test"
end
end
Then you can call it with the namespace in your controllers, views or whatever..
MyAppName::Application::YOUR_GLOBAL_VAR
Another alternative would be using something like settingslogic. With settingslogic, you just create a yml config file and a model (Settings.rb) that points to the config file. Then you can access these settings anywhere in your rails app with:
Settings.my_setting
I've started putting constants and variables like this in the configuration object, e.g.
TestApp::Application.config.foo = 'bar'
TestApp::Application.config.something = { :a => 1, :b => 2 }

Ruby on Rails: an efficient use of a class in lib/ directory

I've been building a text parser. Ideally, it should be a static class:
keywords = Dictionary.parse(text)
However, the parser (lib/dictionary.rb) has to load some data (for instance, 'stop_words.txt') into memory as an array.
Therefore, as I understand, it can't be a static class, since I need a constructor, which would load that data before the parser can be used.
Then:
lib/dictionary.rb
def initialize
#stop_words = load_stop_words
end
models/entry.rb
def parse
#dictionary = Dictionary.new
self.keywords = #dictionary.parse(self.text)
end
But how inefficient is that? Does it mean, that if I have 1000 entries, the Dictionary class loads 'stop_words.txt' 1000 times, even if the contents of the file are almost constant?
I guess, I am missing something here. There must be a better solution - either without creating multiple instances of the Dictionary class, or by loading data only once, when the application is running.
So your pattern is that you would like a single instance of the object ( which is effectively constant and read-only after instantiation ) which is accessible from many callers but instantiates itself the first time it is called?
The name of this pattern is the Singleton and Ruby has it available as a mixin.
I would use an initializer, which is stored in config/initializers and those are only loaded on startup, and perfect to load configuration files or setting up stuff. So your Dictionary is under '/liband in '/config/initializers you create a file called dictionary.rb (or similar, the name is actually not important)
which contains the code to load your keywords.
If you are in Rails (as I assume by the tag and the lib directory) then it doesn't get loaded N times: lib files gets loaded only at Rails booting (if you change them, you need to restart the application) and so stop_words will be loaded just one time. Little example (lib/timenow.rb):
module Timenow
#now = Time.now
def self.doit
Rails.logger.warn "TIME NOW IS: #{#now}"
end
end
In any controller, Timenow.doit logs the time this module was loaded.

Resources