So I maintain a Rails app with more than 150 database tables. And we are experiencing deadlocks at several locations.
After reading through this post https://hackernoon.com/troubleshooting-and-avoiding-deadlocks-mysql-rails-766913f3cfbc and understanding better the different situations. it seems one common pattern we have is due to unique index waiting for each others on concurrent lock.
So I am looking for a way to say in a model that it should not try to insert two at the time, since MySQL will lock the table. I want it as easy as.
class BingoCard < ActiveRecord::Base
protect_table_locks
end
Which would use a Redis base lock, to wrap around the create operations
I already looked into this answer for ideas. Mutex for ActiveRecord Model
I plan on posting my own answer when I have it.
This is my draft implementation.
if there is enough interest, I will make it a gem
# frozen_string_literal: true
module ActiveRecord
module PersistenceRedisLock
private
def _create_record
_lock_manager.lock(_locked_resource_id, _lock_duration) do |_lock_info|
super
end
end
def _locked_resource_id
#TODO: make it a configurable option
"PersistenceRedisLock#{self.class.table_name}"
end
def _lock_duration
#TODO: make it a configurable option
10.seconds # Maybe too long of a default, but this is a proof of concept for now
end
def _lock_manager
##_lock_manager ||= Redlock::Client.new [Ph::Redis.redis_url_for(:red_locks)]
end
end
class Base
def self.protect_table_locks
self.prepend PersistenceRedisLock
end
end
end
Related
I have the following model:
class User < ActiveRecord::Base
def stripe_plan_id
self.stripe_subscription.plan.id
end
def stripe_subscription
customer = Stripe::Customer.retrieve(self.stripe_customer_id)
customer.subscriptions.retrieve(self.stripe_subscription_id)
end
end
I've got the model attribute stripe_plan_id I don't want to it persist in the database using ActiveRecord, but I need to check this parameter a lot. I would like to cache it on my server, and flush it on demand. Ideally I don't want to use redis.
What's the best approach? I'm trying to work out if ||= can be used somehow.
There are alot of ways, i'm assuming you know how to cache already using whatever you have (memcached, redis, rails.cache, etc), let me know if that is not the case. I recommend creating a caching class that gets or reloads cache based on an id. Your memoizing wouldn't work for your case because you want to persist between controllers.
def StripeCache < Struct.new(:user)
def cache_key
"#{user.id}_stripe_plan_id"
end
def get
ReadFromCache(cache_key)
end
def reload
WriteToCache(cache_key, user.stripe_plan_id)
end
end
Then when you want to get this you just call
StripeCache.new(user).get
and to save new stuff you call
StripeCache.new(user).reload
Is a little extra overhead, but will abstract all the reading and writing to and from cache from you.
I've got STI like this:
class Post
end
class Post::Confirmed < Post
end
class Post::Draft < Post
def confirm!
becomes Post::Confirmed
end
end
...# somewhere in controller
# POST /posts/1/confirm
# POST /posts/1/confirm.json
def confirm
#post = Post::Draft.first
#post = #post.confirm! # this is the only way I can reload #post with Post::Confrmed
end
Is it somehow possible to make:
#post.confirm! # I want this #post(Post::Draft) to become Post::Confirmed without reassigning
Or is it just nor RoR way?
Thanks in advance!
The pattern I've found that works best here is having a datetime type field that records when the record was flagged.
For example:
def confirm!
self.confirmed_at = DateTime.now
self.save!
end
Then you can tell when something was confirmed. This comes in especially handy for when you have a situation where something will be flagged but isn't yet, such as setting a publishing date in the future.
Although it might seem a little annoying to not have your STI bag of tricks available, STI is not always the appropriate tool. Generally STI is to differentiate between similar but different models that have a lot of commonality or are used in a common context. It's not supposed to be used to handle different states of a singular model.
What you want in that case is a state-machine type pattern.
How can I implement the Repository or Gateway pattern in Ruby?
I come from a C# world and I usually abstract away my data access but with ActiveRecord as the default data access mechanism in Ruby, it's not obvious how to accomplish that.
What I usually would do in C# is work with abstract interfaces and then have a concrete implementation for EFCustomerRepository, NHibernateCustomerRepository and InMemoryCustomerRepository and depending on the situation I inject the matching concrete implementation.
So now, what’s the Ruby way?!
As far as I understand it, in dynamic languages you would not need something like DI (dependency injection).
And Ruby has powerful language features to allow things like mixins.
But you would define the mixin to use statically on class or module-level?
How do I write my business logic if I want to develop against an in-memory repository and in production I would switch to my ActiveRecord-Repository?
If might be on the wrong path here since I'm used to thinking in a statically typed language. How would someone tackle this task the Ruby way? Basically I want to make my persistence layer abstract and it's implementations interchangeable.
EDIT: I am referring to robert c. martins (unclebob) keynote about architecture
Thanks for any help...
I get what you are saying. I come from a .NET background as well. Abstracting away your business logic & persistance logic is imo a good idea. I haven't found a gem that does it for you yet. But you can easily roll something simple yourself. In the end a repository pattern is basically a class that delegates to your persistance layer.
Here is what I do:
require 'active_support/core_ext/module/attribute_accessors'
class GenericRepository
def initialize(options = {})
#scope = options[:scope]
#association_name = options[:association_name]
end
def self.set_model(model, options = {})
cattr_accessor :model
self.model = model
end
def update(record, attributes)
check_record_matches(record)
record.update_attributes!(attributes)
end
def save(record)
check_record_matches(record)
record.save
end
def destroy(record)
check_record_matches(record)
record.destroy
end
def find_by_id(id)
scoped_model.find(id)
end
def all
scoped_model.all
end
def create(attributes)
scoped_model.create!(attributes)
end
private
def check_record_matches(record)
raise(ArgumentError, "record model doesn't match the model of the repository") if not record.class == self.model
end
def scoped_model
if #scope
#scope.send(#association_name)
else
self.model
end
end
end
And then you could for example have a Post repository.
class PostRepository < GenericRepository
set_model Post
# override all because we also want to fetch the comments in 1 go.
def all
scoped_model.all(:include => :comments)
end
def count()
scoped_model.count
end
end
Just instantiate it in your controller in a before_filter or initialize or wherever. In this case I'm scoping it to the current_user so that it only fetches those records and automatically create posts only for the current user.
def initialize
#post_repository = PostRepository.new(:scope => #current_user, :association_name => 'posts')
end
def index
#posts = #post_repository.all
respond_with #posts, :status => :ok
end
I came across https://github.com/bkeepers/morphine which is a tiny DI framework. It could work for you :) But DI isn't a heavily used pattern in ruby. Also, I instantiate my repos in order to scope them to a current user or something else.
I'm on a quest to find the right way to do just what you ask and do a little write-up about it if I ever do find it. But for now it's already sufficient to make the clean cut between persistance & my controllers. If this is done properly it won't be a big hassle to switch to a different system later on. Or add caching etc.
Well, ActiveRecord already provides abstract persistence layer - it has several different adapters allowing it to use different database backends. Also, it's open-source so you are free to take a look at how it has been achieved.
Upon the first glance you can see that it also has an AbstractAdapter that all other adapters inherit, however, as Ruby is dynamic, duck-typing language, AbstractAdapter doesn't have to contain abstract methods which will be overridden in children classes, neither defines a "contract" that they should honour.
Edit:
Here's a simple sketch on how you could abstract away your storage in Ruby, not sure which pattern exactly it is:
# say you have an AR model of a person
class Person < ActiveRecord::Base
end
# and in-memory store of persons (simply, a hash)
IN_MEMORY_STORE = {
:Person => ['Tim', 'Tom', 'Tumb']
}
# this will abstract access
class MyAbstractModel
def initialize item, adapter
#item = item
#adapter = adapter
end
# get all elements from the store
def all
case #adapter
when :active_record
# pull from database:
Object.const_get(#item).all
when :in_memory_store
# get from in-memory store
IN_MEMORY_STORE[#item]
else
raise "Unknown adapter"
end
end
end
# get all Persons from in-memory storage...
p MyAbstractModel.new(:Person, :in_memory_store).all
# ...and from a database
p MyAbstractModel.new(:Person, :active_record).all
#serverinfo, I don't know much about C#. But when I came to Ruby from a Java/C background, I was blown away when I realized how flexible this language really is. You say that your real problem here is to "abstract away your persistence layer and make it exchangeable". You also asked "how will I write the business logic".
I suggest that you throw away your preconceptions and ask yourself: "how would I like to express data access/storage within my business logic layer"? Don't worry about what you think can or can't be done; if you can figure out how you would like the interface to work, there is probably a way it can be done in Ruby.
You will also have to decide how you want to specify the concrete implementation to be used. Is it possible you will want to use a different data store for different model objects? Might you want to switch at run-time? Would you like to specify the backend to be used in a configuration file, or in code? If you can decide what you want to do, there are lots of people on Stack Overflow who can help you figure out how to do it.
I'd like to override the setter for an association, but write_attribute() isn't working - probably because that method only works for database columns.
I have tried super(), but that doesn't work either (didn't think it would... but it was worth a guess).
How do I override the setter? Here is what I am trying to do:
def parent=(value)
# this line needs to be changed
write_attribute(:parent, value)
if value.subject.start_with?('Re:')
self.subject = "#{value.subject}"
else
self.subject = "Re: #{value.subject}"
end
self.receivers << value.sender
end
What worked for me is the following:
def parent=(new_parent)
# do stuff before setting the new parent...
association(:parent).writer(new_parent)
end
I found one way to do it, but I am disturbed by it:
alias_method :old_parent=, :parent=
def parent=(value)
self.old_parent = value
if value.subject.start_with?('Re:')
self.subject = "#{value.subject}"
else
self.subject = "Re: #{value.subject}"
end
self.receivers << value.sender
end
One thing I don't necessarily like about Rails is that whenever you want to do something that is out of the norm just a bit - but not unreasonable by any means - the "how" is very different than what your intuition would come up with.
It's not a problem when you know the exceptions, but when you're learning, this sort of irregularity and inconsistency on how to do things makes it harder to learn - not easier.
Java might be initially harder to learn, but it's way more consistent. Your intuition can take you a lot further once you think in Java. This is not true once you think in Rails. Rails is about memorization of methods to call and memorization on how to do things. In java, you can reason it out a lot more... and intellisense fills in the rest.
I'm just disappointed. This is a reoccurring pattern for me - I want do something that is just "a little more complex" than the framework examples... and the "how" is inconsistent and takes 30 minutes or maybe even hours to locate and find the answer for it.
In Rails 4.2.1 doc:
# Association methods are generated in a module that is included into the model class,
# which allows you to easily override with your own methods and call the original
# generated method with +super+. For example:
#
# class Car < ActiveRecord::Base
# belongs_to :owner
# belongs_to :old_owner
# def owner=(new_owner)
# self.old_owner = self.owner
# super
# end
# end
Instead of
def parent=(value)
write_attribute(:parent, value)
end
Couldn't you just do:
def parent=(parent)
parent_id = parent.id
end
I've found a way to make this work, but am curious about a better way / the Rails 3 way. (I'm using 2.3.5 still, but hope to migrate around New Year's.)
The situation: I've got two layers of module inheritance, the second layer gets mixed into a Rails model. Both modules define validation methods and I'd like both of them to attach the validations to the base class, but because of the two levels of inheritance, the following doesn't work:
def self.included(base)
base.validate :yadda_yadda
end
When that module is included by another module, the interpreter grinds to a screeching halt because Modules don't know about ActiveRecord::Validations. Including the validations module begs the question of "where is save?" thanks to alias_method.
The following works, as long as you remember to call super whenever you override validate(). I don't trust myself or future maintainers to remember that, so I'd like to use the validate :yadda_yadda idiom instead, if possible.
module Grandpa
def validate
must_be_ok
end
def must_be_ok
errors.add_to_base("#{self} wasn't ok")
end
end
module Dad
include Grandpa
def validate
super
must_be_ok_too
end
def must_be_ok_too
errors.add_to_base("#{self} wasn't ok either")
end
end
class Kid < ActiveRecord::Base
include Dad
validate :must_be_ok_three
def must_be_ok_three
errors.add_to_base("#{self} wasn't ok furthermore")
end
end
Suggestions? Tips for Rails 3 approach? I don't think the validations API has changed that much.
I solved it (when I ran into the same problem, but with something other than validation).
Short answer: you can call send(:included, base) on the module you want to bring in. Within the higher-up included() definition, you need to check whether the base is a Class or a Module.
Why would you ever want to do this? Well, I've got some modules that extract some common functionality out of my models. For instance, the module HasAllocable sets up a polymorphic belongs_to relationship, and a getter/setter pair for a virtual attribute. Now I have another module that needs to pull in HasAllocable, to spare the base classes from having to remember it.
I'd be interested to know whether this smells funny to anyone. I haven't seen anything like it on the web, so I wonder if multiple layers of model inheritance is more of an antipattern.
module Grandpa
def self.included(base)
if base.kind_of?(Class)
base.validate :must_be_ok
end
end
end
module Dad
include Grandpa
def self.included(base)
if base.kind_of?(Class)
# you can do this
#base.send(:include, Grandpa)
# you can also do this
Grandpa.send(:included, base)
# this does not invoke Grandpa.included(Kid)
#super(base)
base.validate :must_be_ok_too
end
end
end
class Kid < ActiveRecord::Base
include Dad
validate :must_be_ok_three
end