require "forwardable"

module FakeSQS
  class MemoryDatabase
    extend Forwardable

    def_delegators :@queues,
      :[], :[]=, :delete, :each, :select, :values

    def initialize
      @in_transaction = false
    end

    def load
      @queues = {}
    end

    def transaction
      if @in_transaction
        raise "Already in transaction"
      else
        @in_transaction = true
        begin
          yield
        ensure
          @in_transaction = false
        end
      end
    end

    def reset
      @queues = {}
    end

  end
end

require "forwardable"
require "thread"

module FakeSQS
  class MemoryDatabase
    extend Forwardable

    def_delegators :@queues,
      :[], :[]=, :delete, :each, :select, :values

    def initialize
      @semaphore = Mutex.new
    end

    def load
      @queues = {}
    end

    def transaction
      @semaphore.synchronize do
        yield
      end
    end

    def reset
      @queues = {}
    end

  end
end

Use a Mutex to make MemoryDatabase genuinely thread safe.
Use a Mutex to make MemoryDatabase genuinely thread safe.

While the "check and raise" boolean method sometimes works, it quickly
starts raising errors and spamming the console when run under a modern
threaded server like thin or puma. Since Ruby has a reliable, genuine
mutex, use it so that instead of tossing away any conflicting
transactions, they just line up and go one at a time.
