0.0
The project is in a healthy, maintained state
Using In-Memory Databases to Work with Rails Active Record Locks
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Runtime

 Project Readme

RailsSoftLock – Group Locking for ApplicationRecord by Attribute

Overview

The RailsSoftLock gem provides group-level locking for Rails ApplicationRecord objects based on a shared attribute. Instead of individually locking each database record (which can be expensive and complex), it creates and manages a single in-memory lock for the entire group via the attribute. This reduces database contention while maintaining thread safety.

Key Features

Lightweight Group Locking:

    Locks records sharing the same attribute value via an in-memory database (e.g., Redis, NATS).

    Avoids expensive row-level locks in your primary database.

ActiveRecord Integration:

    Extends Rails’ built-in locking mechanisms with adapters for in-memory stores.

    Supports scoped uniqueness (e.g., lock groups by account_id + category).

Beyond Locking:

    Can also mark/tag groups of records (e.g., flag all records with project_id=123 as "favorites").

    Useful for batch operations or state management (e.g., "processing", "archived").

Current Status

Active Development: New features and optimizations in progress.

Available Adapters: Redis and Redis-compatible databases (e.g., Valkey).

Installation

Install the gem and add to the application's Gemfile:

# Stable version
gem "rails_soft_lock"
# Last version
gem "rails_soft_lock", git: "https://github.com/sergey-arkhipov/rails_soft_lock.git"

When using Redis as an adapter and having REDIS_URL in config/redis.yml it is not necessary to install the initializer. Only when need to replace some standard settings, User model, for example, or adapter.

bundle install

Run rake task

rake rails_soft_lock:install

This will install config for gem, if file does not exists

## config/initializers/rails_soft_lock.rb
# frozen_string_literal: true

# Configuration for RailsSoftLock gem
# This file sets up the adapter and options for soft locking Active Record models
require "rails_soft_lock"
RailsSoftLock.configure do |config|
  # Specify the adapter for storing locks
  config.adapter = :redis

  # Configuration for the Redis adapter
  config.adapter_options = {
    redis: Rails.application.config_for(:redis).merge(
      timeout: 5
    )
  }

You can add any modification there.

Gem use ConnectionPool inside for safety connect to Redis adapter (now inplemented)

Usage

Gem assumes that the User model is used to determine the user who sets the lock.

Another model for setting the attribute of the blocking user can be specified in the configuration. The model ID is used for blocking.

RailsSoftLock.configure do |config|
...
  # (Optional) Model class for locked_by lookups
  config.locked_by_class = "User"


end

Model < ApplicationRecord should include RailsSoftLock::ModelExtensions and acts_as_locked_by with acts_as_locked_scope should be set, for example

class Article < ApplicationRecord
  include RailsSoftLock::ModelExtensions

  acts_as_locked_by: attribyte, scope: -> { 'scope_result'}

See spec/rails_soft_lock/model_extensions_spec.rb for implemented methods

Understanding the lock_or_find Method

The lock_or_find method returns a hash with the following structure: ruby

{ has_locked: false, locked_by: user.id }

Key Points:

has_locked: false indicates that the object was not locked prior to this operation.

    Note: This does not refer to the success/failure of the lock attempt itself.

How locking works:

    Since this is an in-memory database designed for fast access, the method:

        Sets the lock (if no lock existed).

        Reports (has_locked: false) that no prior lock was present.

        Returns the ID of the user who now holds the lock.

    If the object was already locked, it returns:
    ruby

{ has_locked: true, locked_by: <existing_lock_user_id> }

In this case, the lock remains unchanged (no new lock is set).

Development

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.

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 the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rails_soft_lock. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the RailsSoftLock project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.