Skip to content

End of Life Ruby 3.2 has reached end of life and gets no more fixes. Switch to Ruby 4.0 →

class method

Fiber.new

Fiber.new(blocking: false, storage: true) { |*args| ... } → fiber

Creates new Fiber. Initially, the fiber is not running and can be resumed with resume. Arguments to the first resume call will be passed to the block:

Example
f = Fiber.new do |initial|
   current = initial
   loop do
     puts "current: #{current.inspect}"
     current = Fiber.yield
   end
end
f.resume(100)     # prints: current: 100
f.resume(1, 2, 3) # prints: current: [1, 2, 3]
f.resume          # prints: current: nil
# ... and so on ...

If blocking: false is passed to Fiber.new, and current thread has a Fiber.scheduler defined, the Fiber becomes non-blocking (see “Non-blocking Fibers” section in class docs).

If the storage is unspecified, the default is to inherit a copy of the storage from the current fiber. This is the same as specifying storage: true.

Example
Fiber[:x] = 1
Fiber.new do
  Fiber[:x] # => 1
  Fiber[:x] = 2
end.resume
Fiber[:x] # => 1

If the given storage is nil, this function will lazy initialize the internal storage, which starts as an empty hash.

Example
Fiber[:x] = "Hello World"
Fiber.new(storage: nil) do
  Fiber[:x] # nil
end

Otherwise, the given storage is used as the new fiber’s storage, and it must be an instance of Hash.

Explicitly using storage: true is currently experimental and may change in the future.

Ruby version changes

  1. 3.2
    • Introduce Fiber.[] and Fiber.[]= for inheritable fiber storage. Introduce Fiber#storage and Fiber#storage= (experimental) for getting and resetting the current storage. Introduce Fiber.new(storage:) for setting the storage when creating a fiber. [Feature #19078]

      Existing Thread and Fiber local variables can be tricky to use. Thread-local variables are shared between all fibers, making it hard to isolate, while Fiber-local variables can be hard to share. It is often desirable to define unit of execution (“execution context”) such that some state is shared between all fibers and threads created in that context. This is what Fiber storage provides.

      Example
      def log(message)
        puts "#{Fiber[:request_id]}: #{message}"
      end
      
      def handle_requests
        while request = read_request
          Fiber.schedule do
            Fiber[:request_id] = SecureRandom.uuid
      
            request.messages.each do |message|
              Fiber.schedule do
                log("Handling #{message}") # Log includes inherited request_id.
              end
            end
          end
        end
      end
      

      You should generally consider Fiber storage for any state which you want to be shared implicitly between all fibers and threads created in a given context, e.g. a connection pool, a request id, a logger level, environment variables, configuration, etc.

  2. 3.0
See also .current_scheduler .schedule .current .scheduler also in 4.1 · 4.0 · 3.4 · 3.3 · 3.1 · 3.0