### Install async-safe Gem Source: https://github.com/socketry/async-safe/blob/main/guides/getting-started/readme.md Add the async-safe gem to your project's dependencies using Bundler. ```bash $ bundle add async-safe ``` -------------------------------- ### Immutable Object Example (Ruby) Source: https://github.com/socketry/async-safe/blob/main/guides/getting-started/readme.md Demonstrates creating an immutable object by freezing instance variables and the entire object. This pattern is safe as its state cannot be modified after initialization. ```ruby class ImmutableUser def initialize(name, email) @name = name.freeze @email = email.freeze freeze # Entire object is frozen end attr_reader :name, :email end ``` -------------------------------- ### Pure Function Example (Ruby) Source: https://github.com/socketry/async-safe/blob/main/guides/getting-started/readme.md Illustrates a pure function that performs a computation without modifying any instance state. Such functions are inherently thread-safe and predictable. ```ruby class Calculator def add(a, b) a + b # No instance state, pure computation end end ``` -------------------------------- ### Thread-Safe Queue Example (Ruby) Source: https://github.com/socketry/async-safe/blob/main/guides/getting-started/readme.md Shows how to implement a thread-safe queue using Ruby's built-in `Thread::Queue`. This class is explicitly marked as `ASYNC_SAFE` and delegates operations to the underlying thread-safe primitive. ```ruby class SafeQueue ASYNC_SAFE = true # Explicitly marked def initialize @queue = Thread::Queue.new # Thread-safe internally end def push(item) @queue.push(item) # Delegates to thread-safe queue end end ``` -------------------------------- ### Enable Global Monitoring in Ruby Source: https://github.com/socketry/async-safe/blob/main/guides/getting-started/readme.md Enable async-safe monitoring across your application. This typically involves requiring the gem and calling `enable!`, often in test or development environments. ```ruby require 'async/safe' # Enable monitoring Async::Safe.enable! # Your concurrent code here... ``` -------------------------------- ### Mutable Instance State Example (Ruby) Source: https://github.com/socketry/async-safe/blob/main/guides/getting-started/readme.md Demonstrates an unsafe pattern with mutable instance state using a counter. The `increment` method modifies `@count`, which can lead to race conditions in concurrent environments and is marked `ASYNC_SAFE = false`. ```ruby class Counter ASYNC_SAFE = false # Enable tracking def initialize @count = 0 end def increment @count += 1 # Reads and writes @count (race condition!) end end ``` -------------------------------- ### Mixed Safety Configuration (Ruby) Source: https://github.com/socketry/async-safe/blob/main/guides/getting-started/readme.md Demonstrates a class with mixed safety using a hash configuration for `ASYNC_SAFE`. This allows distinguishing between safe read operations and unsafe state modification methods within the same class. ```ruby class MixedClass ASYNC_SAFE = { read_config: true, # Safe: only reads frozen data update_state: false # Unsafe: modifies mutable state }.freeze def initialize @config = {setting: "value"}.freeze @state = {count: 0} end def read_config @config[:setting] # Safe: frozen hash end def update_state @state[:count] += 1 # Unsafe: mutates state end end ``` -------------------------------- ### Lazy Initialization Example (Ruby) Source: https://github.com/socketry/async-safe/blob/main/guides/getting-started/readme.md Highlights an unsafe lazy initialization pattern using `||=`. This operation is not atomic and can lead to race conditions if multiple threads attempt to initialize the data simultaneously, hence `ASYNC_SAFE = false`. ```ruby class DataLoader ASYNC_SAFE = false # Enable tracking def data @data ||= load_data # Not atomic! (race condition) end end ``` -------------------------------- ### Stateful Iteration Example (Ruby) Source: https://github.com/socketry/async-safe/blob/main/guides/getting-started/readme.md Presents an unsafe pattern involving stateful iteration where an index is mutated during reading. This class is marked `ASYNC_SAFE = false` due to the modification of `@index`. ```ruby class Reader ASYNC_SAFE = false # Enable tracking def initialize(data) @data = data @index = 0 end def read value = @data[@index] @index += 1 # Mutates state value end end ``` -------------------------------- ### Integrate async-safe with Ruby Tests Source: https://github.com/socketry/async-safe/blob/main/guides/getting-started/readme.md Add async-safe integration to your test suite helper file to automatically fail tests upon detecting thread safety violations. ```ruby require 'async/safe' Async::Safe.enable! ``` -------------------------------- ### Sequential vs Concurrent Access in Ruby with Async::Safe Source: https://context7.com/socketry/async-safe/llms.txt Illustrates the difference between allowed sequential access and detected concurrent access in Ruby using `Async::Safe`. The example demonstrates that sequential calls to a method (`read_chunk`) from different fibers are permitted, highlighting the core purpose of `Async::Safe` in preventing simultaneous access. ```ruby require 'async/safe' require 'async' class Document ASYNC_SAFE = false def initialize(content) @content = content @position = 0 end def read_chunk chunk = @content[@position, 10] @position += 10 chunk end end Async::Safe.enable! doc = Document.new("Hello World" * 100) # ✅ Sequential access - ALLOWED doc.read_chunk # Main fiber reads Fiber.new do doc.read_chunk # Different fiber reads after main completes - OK end.resume doc.read_chunk # Main fiber reads again - OK ``` -------------------------------- ### Configure Per-Method Safety with Hash or Array Source: https://context7.com/socketry/async-safe/llms.txt This example showcases configuring per-method safety using either a hash or an array for the `ASYNC_SAFE` constant. The hash configuration allows specifying safety for individual methods by name, while the array lists methods considered safe for concurrent access. Methods not explicitly marked are tracked. ```ruby require 'async/safe' # Hash-based configuration class MixedClass ASYNC_SAFE = { read_config: true, # Safe: only reads frozen data update_state: false # Unsafe: modifies mutable state }.freeze def initialize @config = {setting: "value"}.freeze @state = {count: 0} end def read_config @config[:setting] # Safe - frozen hash end def update_state @state[:count] += 1 # Unsafe - mutates state end end # Array-based configuration class ReadOnlyClass ASYNC_SAFE = [:read, :inspect, :to_s].freeze def read @data # Safe to call concurrently end def inspect "#" # Safe to call concurrently end def write(value) @data = value # NOT in array - will be tracked end end Async::Safe.enable! obj = MixedClass.new Fiber.new do obj.read_config # OK - marked as async-safe end.resume obj.update_state # Tracked for concurrent access readonly = ReadOnlyClass.new readonly.read # OK concurrently readonly.inspect # OK concurrently readonly.write("test") # Tracked - not in ASYNC_SAFE array ``` -------------------------------- ### Guard-Based Concurrency for Streams in Ruby Source: https://github.com/socketry/async-safe/blob/main/guides/getting-started/readme.md Implement custom concurrency guards for a `Stream` class to allow concurrent reads and writes while preventing concurrent reads or writes. ```ruby class Stream def self.async_safe?(method) case method when :read then :readable when :write then :writable else false end end def read; end def write(data); end end ``` -------------------------------- ### Mark Specific Methods as Async-Safe in Ruby Source: https://github.com/socketry/async-safe/blob/main/guides/getting-started/readme.md Use a hash or an array to specify which methods within a class are async-safe. Methods not listed are tracked for concurrent access. ```ruby class MixedSafety ASYNC_SAFE = { safe_read: true, increment: false }.freeze def initialize(data) @data = data @count = 0 end def safe_read @data end def increment @count += 1 end end obj = MixedSafety.new("data") Fiber.schedule do obj.safe_read obj.increment end ``` ```ruby class MyClass ASYNC_SAFE = [:read, :inspect].freeze # read and inspect are async-safe # all other methods will be tracked end ``` -------------------------------- ### Mark Class as Single-Owner with ASYNC_SAFE Constant Source: https://context7.com/socketry/async-safe/llms.txt This example shows how to mark a class as requiring single-owner tracking by setting the `ASYNC_SAFE` constant to `false`. It illustrates sequential access within different fibers being allowed, while concurrent access to an instance of `MyBody` would raise a `ViolationError` after enabling monitoring. ```ruby require 'async/safe' # Mark entire class as single-owner class MyBody ASYNC_SAFE = false # Enable tracking for this class def initialize(chunks) @chunks = chunks @index = 0 end def read chunk = @chunks[@index] @index += 1 chunk end end Async::Safe.enable! body = MyBody.new(["chunk1", "chunk2", "chunk3"]) body.read # Main fiber - OK # Sequential access across fibers is allowed Fiber.new do body.read # Different fiber - OK, sequential access end.resume # Concurrent access will raise ViolationError require 'async' Async do |task| task.async { body.read } # Fiber A starts reading task.async { body.read } # Fiber B tries concurrently - ViolationError! end ``` -------------------------------- ### Detect Concurrent Access in Ruby Source: https://github.com/socketry/async-safe/blob/main/guides/getting-started/readme.md Demonstrates how async-safe detects concurrent access to an object (`Counter`) across different fibers within an `Async` task. Sequential access is allowed, but simultaneous modification triggers a violation. ```ruby require 'async' counter = Counter.new counter.increment Async do |task| task.async do counter.increment # Fiber A accessing sleep 0.1 # ... method is still running end task.async do sleep 0.05 # Wait for Fiber A to start counter.increment # 💥 Concurrent access detected! end end ``` -------------------------------- ### Mark Class as Async-Safe in Ruby Source: https://github.com/socketry/async-safe/blob/main/guides/getting-started/readme.md Mark an entire class (`MyQueue`) as safe for concurrent access using `async_safe!`. Alternatively, set the `ASYNC_SAFE` constant to `true` or provide a hash/array for fine-grained control. ```ruby class MyQueue async_safe! def initialize @queue = Thread::Queue.new end def push(item) @queue.push(item) end def pop @queue.pop end end queue = MyQueue.new queue.push("item") Fiber.schedule do queue.push("another") # ✅ OK - class is marked async-safe end ``` ```ruby class MyQueue ASYNC_SAFE = true # ... implementation end ``` ```ruby class MixedClass ASYNC_SAFE = { read: true, write: false }.freeze # ... implementation end ``` -------------------------------- ### Enable Tracking for Specific Class in Ruby Source: https://github.com/socketry/async-safe/blob/main/guides/getting-started/readme.md Mark a specific class (`MyBody`) as not async-safe by setting `ASYNC_SAFE = false`. This enables async-safe to track concurrent access to instances of this class. ```ruby class MyBody ASYNC_SAFE = false # Enable tracking for this class def initialize(chunks) @chunks = chunks @index = 0 end def read chunk = @chunks[@index] @index += 1 chunk end end body = MyBody.new(["a", "b", "c"]) body.read # Main fiber Fiber.schedule do body.read # ✅ OK - sequential access is allowed end # But concurrent access is detected: require 'async' Async do |task| task.async { body.read } task.async { body.read } end ``` -------------------------------- ### Guard-Based Concurrency in Ruby with Async::Safe Source: https://context7.com/socketry/async-safe/llms.txt Implement advanced concurrency control using guards for operations that can run independently. This example shows a `Stream` class where `read` and `write` operations can occur concurrently because they are assigned different guards (`:readable` and `:writable`), while `close` is tracked with a single guard. ```ruby require 'async/safe' require 'async' # Stream with independent read/write operations class Stream def self.async_safe?(method) case method when :read then :readable # Read guard when :write then :writable # Write guard else false # Other methods tracked with single guard end end def initialize @read_buffer = [] @write_buffer = [] end def read # Can run concurrently with write (different guards) @read_buffer.shift end def write(data) # Can run concurrently with read (different guards) @write_buffer.push(data) end def close # Cannot run concurrently with anything (single-guard tracking) @read_buffer.clear @write_buffer.clear end end Async::Safe.enable! stream = Stream.new Async do |task| # These CAN run concurrently - different guards reader = task.async do sleep 0.05 stream.read # :readable guard end writer = task.async do stream.write("data") # :writable guard - OK, different guard end reader.wait writer.wait end # These CANNOT run concurrently - same guard Async do |task| task.async { stream.read } # :readable guard task.async do sleep 0.05 stream.read # :readable guard - ViolationError if overlapping! end.wait end Async::Safe.disable! ``` -------------------------------- ### Run Tests with async-safe Enabled Source: https://github.com/socketry/async-safe/blob/main/context/getting-started.md Command to run tests after integrating the async-safe gem. Any detected thread safety violations will cause the test suite to fail. ```bash $ bundle exec sus ``` -------------------------------- ### Per-Method Async-Safety Configuration (Hash) Source: https://github.com/socketry/async-safe/blob/main/context/getting-started.md Configures async-safety for a class using a hash where keys are method names and values are booleans indicating safety. This allows fine-grained control over which methods are monitored. ```ruby class MixedClass ASYNC_SAFE = { read: true, # This method is async-safe write: false # This method is NOT async-safe }.freeze # ... implementation end ``` -------------------------------- ### Handling ViolationError Exceptions in Ruby Source: https://context7.com/socketry/async-safe/llms.txt Demonstrates how to catch and handle `Async::Safe::ViolationError` exceptions that occur due to thread safety violations. It shows how to access detailed information about the violation, including the object, methods, owner fiber, and accessing fiber, along with a JSON representation of the error. ```ruby require 'async/safe' require 'async' class UnsafeCounter ASYNC_SAFE = false def initialize @count = 0 end def slow_increment @count += 1 sleep 0.1 # Simulate work @count end end Async::Safe.enable! counter = UnsafeCounter.new begin Async do |task| # Start first fiber task.async do counter.slow_increment # Takes 0.1 seconds end # Start second fiber while first is still running task.async do sleep 0.05 # Wait for first to start counter.slow_increment # Concurrent access detected! end.wait end rescue Async::Safe::ViolationError => e puts "Violation detected!" puts "Message: #{e.message}" # => "Thread safety violation detected!" # => "Object: ##slow_increment" # => "Owner: #" # => "Accessed by: #" # Access error details puts "Method: #{e.method}" puts "Owner fiber: #{e.owner.inspect}" puts "Current fiber: #{e.current.inspect}" # Get JSON representation error_data = e.as_json # => {:object_class=>..., :method=>:slow_increment, # :owner=>{:name=>"...", :backtrace=>[...]}, # :current=>{:name=>"...", :backtrace=>[...]}} end Async::Safe.disable! ``` -------------------------------- ### Sequential Access Allowed Source: https://github.com/socketry/async-safe/blob/main/context/getting-started.md Demonstrates that async-safe allows sequential access to an object from different fibers. A violation is only raised on simultaneous access. ```ruby Async::Safe.enable! request = Request.new("http://example.com") request.process # Main fiber Fiber.new do # No problem - sequential access is allowed request.process # ✅ OK end.resume ``` -------------------------------- ### Integrating Async::Safe with Ruby Test Suites Source: https://context7.com/socketry/async-safe/llms.txt Shows how to enable `Async::Safe` monitoring within test configurations (e.g., `config/sus.rb` or `spec/spec_helper.rb`) to automatically catch concurrency bugs during test execution. Violations will result in immediate test failures with detailed error messages. ```ruby # config/sus.rb or spec/spec_helper.rb require 'async/safe' # Enable monitoring for all tests Async::Safe.enable! # Example test describe "Concurrent request processing" do it "processes requests safely" do processor = RequestProcessor.new # Has ASYNC_SAFE = false # Test will fail if concurrent access occurs Async do |task| task.async { processor.handle(request1) } task.async { processor.handle(request2) } end end end # Run tests normally # $ bundle exec sus # Any violations will cause immediate test failures with detailed error messages ``` -------------------------------- ### Guard-Based Concurrency Configuration Source: https://github.com/socketry/async-safe/blob/main/context/getting-started.md Shows how to configure a class to allow concurrent access for different types of operations using distinct guards. The `async_safe?` class method returns a symbol representing the guard for a given method. ```ruby class Stream def self.async_safe?(method) case method when :read then :readable when :write then :writable else false end end def read; end def write(data); end end ``` -------------------------------- ### Enable Thread Safety Monitoring with Async::Safe Source: https://context7.com/socketry/async-safe/llms.txt This snippet demonstrates how to enable and disable thread safety monitoring using `Async::Safe.enable!` and `Async::Safe.disable!`. It also shows how to mark a class as single-owner by setting `ASYNC_SAFE = false`, preventing concurrent access to its instances. ```ruby require 'async/safe' # Enable monitoring (typically in test suite or development) Async::Safe.enable! # Your concurrent code runs here with monitoring active class Counter ASYNC_SAFE = false # Mark as single-owner def initialize @count = 0 end def increment @count += 1 end end counter = Counter.new counter.increment # Disable monitoring when done Async::Safe.disable! ``` -------------------------------- ### Marking Specific Methods as Async-Safe (Hash) Source: https://github.com/socketry/async-safe/blob/main/context/getting-started.md Specifies which methods within a class are async-safe by providing a hash to the `ASYNC_SAFE` constant. Methods not listed or marked `false` will be monitored. ```ruby class MixedSafety ASYNC_SAFE = { safe_read: true, # This method is async-safe increment: false # This method is NOT async-safe }.freeze def initialize(data) @data = data @count = 0 end def safe_read @data # Async-safe method end def increment @count += 1 # Not async-safe - will be tracked end end obj = MixedSafety.new("data") Fiber.schedule do obj.safe_read # ✅ OK - method is marked async-safe obj.increment # 💥 Raises Async::Safe::ViolationError! end ``` -------------------------------- ### Mark Class as Async-Safe with async_safe! Method Source: https://context7.com/socketry/async-safe/llms.txt This code demonstrates using the `async_safe!` class method to mark entire classes or specific methods as safe for concurrent access. It shows a `SafeQueue` class marked as `async_safe!`, allowing concurrent pushes and pops. It also illustrates per-method configuration using a hash for mixed safety levels. ```ruby require 'async/safe' # Mark entire class as async-safe class SafeQueue async_safe! # No tracking needed def initialize @queue = Thread::Queue.new # Thread-safe primitive end def push(item) @queue.push(item) end def pop @queue.pop end end Async::Safe.enable! queue = SafeQueue.new queue.push("item1") # Concurrent access is allowed Fiber.new do queue.push("item2") # OK - class is marked async-safe end.resume # Per-method configuration with hash class MixedSafety async_safe!(safe_read: true, increment: false) def initialize(data) @data = data.freeze @count = 0 end def safe_read @data # Async-safe method end def increment @count += 1 # Not async-safe - will be tracked end end obj = MixedSafety.new("frozen data") obj.safe_read # OK from any fiber Fiber.new do obj.safe_read # OK - method is marked async-safe obj.increment # Tracked - concurrent access detected if overlapping end.resume ``` -------------------------------- ### Query Async Safety with async_safe? Method Source: https://context7.com/socketry/async-safe/llms.txt This snippet shows how to use the `async_safe?` method to query whether a class or a specific method is marked as thread-safe by Async::Safe. It returns `true` if the entire class is marked safe, or `false` if it contains a mix of safe and unsafe methods. ```ruby require 'async/safe' class ExampleClass ASYNC_SAFE = { safe_method: true, unsafe_method: false }.freeze end # Query class-level safety ExampleClass.async_safe? # => false (has mixed methods) ``` -------------------------------- ### Single-Owner Model Configuration Source: https://github.com/socketry/async-safe/blob/main/context/getting-started.md Enables tracking for a specific class by setting the `ASYNC_SAFE` constant to `false`. This class's methods will be monitored for concurrent access violations. ```ruby class MyBody ASYNC_SAFE = false # Enable tracking for this class def initialize(chunks) @chunks = chunks @index = 0 end def read chunk = @chunks[@index] @index += 1 chunk end end body = MyBody.new(["a", "b", "c"]) body.read # Main fiber Fiber.schedule do body.read # ✅ OK - sequential access is allowed end # But concurrent access is detected: require 'async' Async do |task| task.async { body.read } task.async { body.read } end ``` -------------------------------- ### Marking Async-Safe Methods with Array Source: https://github.com/socketry/async-safe/blob/main/context/getting-started.md Declares a list of methods within a class that are considered async-safe. Any method not included in this array will be subject to concurrent access monitoring. ```ruby class MyClass ASYNC_SAFE = [:read, :inspect].freeze # read and inspect are async-safe # all other methods will be tracked end ``` -------------------------------- ### Manual Async-Safe Class Marking Source: https://github.com/socketry/async-safe/blob/main/context/getting-started.md Manually marks a class as async-safe by setting the `ASYNC_SAFE` constant to `true`. ```ruby class MyQueue ASYNC_SAFE = true # ... implementation end ``` -------------------------------- ### Querying Async Safety Status in Ruby Source: https://context7.com/socketry/async-safe/llms.txt Check if methods on a class are considered safe for asynchronous execution. It supports classes with explicit `ASYNC_SAFE` constants (boolean or array-based) and provides defaults when no constant is defined. ```ruby require 'async/safe' # Example using ASYNC_SAFE constant (boolean) class ExampleClass ASYNC_SAFE = true end ExampleClass.async_safe?(:safe_method) # => true ExampleClass.async_safe?(:unsafe_method) # => false ExampleClass.async_safe?(:unknown_method) # => false (defaults to tracked) # Class with no ASYNC_SAFE constant class RegularClass end RegularClass.async_safe? # => true (default: async-safe) RegularClass.async_safe?(:any_method) # => true (default: async-safe) # Array-based configuration class ArrayConfigClass ASYNC_SAFE = [:read, :inspect].freeze end ArrayConfigClass.async_safe?(:read) # => true ArrayConfigClass.async_safe?(:inspect) # => true ArrayConfigClass.async_safe?(:write) # => false (not in array) ArrayConfigClass.async_safe? # => false (has tracked methods) ``` -------------------------------- ### Detecting Concurrent Access with Async-Safe (Ruby) Source: https://context7.com/socketry/async-safe/llms.txt This Ruby code demonstrates how Async-Safe detects concurrent access violations. A `SlowDocument` class is marked with `ASYNC_SAFE = false`. When two fibers attempt to modify the `@content` instance variable concurrently using `slow_process`, Async-Safe intercepts the second access while the first is still in progress, raising a `ViolationError`. ```ruby class SlowDocument ASYNC_SAFE = false def initialize(content) @content = content end def slow_process # Method takes time to complete @content.upcase! sleep 0.1 @content end end slow_doc = SlowDocument.new("test") begin Async do |task| # Fiber A starts processing task.async do slow_doc.slow_process # Starts at T=0, completes at T=0.1 end # Fiber B tries to access while A is still running task.async do sleep 0.05 # Wait until T=0.05 slow_doc.slow_process # ViolationError! A is still running end.wait end rescue Async::Safe::ViolationError => e puts "Concurrent access caught: #{e.message}" end Async::Safe.disable! ``` -------------------------------- ### Marking Classes as Async-Safe Source: https://github.com/socketry/async-safe/blob/main/context/getting-started.md Marks an entire class as safe for concurrent access using the `async_safe!` class method. This prevents async-safe from monitoring this class. ```ruby class MyQueue async_safe! def initialize @queue = Thread::Queue.new end def push(item) @queue.push(item) end def pop @queue.pop end end ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.