ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
From: "Eregon (Benoit Daloze)" <noreply@ruby-lang.org>
To: ruby-core@neon.ruby-lang.org
Subject: [ruby-core:110406] [Ruby master Feature#19062] Introduce `Fiber#locals` for shared inheritable state.
Date: Tue, 18 Oct 2022 12:32:49 +0000 (UTC)	[thread overview]
Message-ID: <redmine.journal-99716.20221018123249.3344@ruby-lang.org> (raw)
In-Reply-To: redmine.issue-19062.20221016103104.3344@ruby-lang.org

Issue #19062 has been updated by Eregon (Benoit Daloze).


> One of the problems I'm trying to solve is behavioural changes due to the internal fiber of enumerator. Can you propose some other way to fix this?

Maybe Enumerator-created Fiber should always use the Fiber locals of the caller Fiber?

IMHO Enumerator-created Fiber are too slow and should not be used, so it's rarely a problem in practice.
Also I think the `Enumerator#{peek,next}` API feels unidiomatic and there is rarely if ever a good reason to use it, and IIRC that's the only two methods creating a Fiber in Enumerator.

----------------------------------------
Feature #19062: Introduce `Fiber#locals` for shared inheritable state.
https://bugs.ruby-lang.org/issues/19062#change-99716

* Author: ioquatix (Samuel Williams)
* Status: Open
* Priority: Normal
* Assignee: ioquatix (Samuel Williams)
----------------------------------------
After exploring <https://bugs.ruby-lang.org/issues/19058>, I felt uncomfortable about the performance of copying lots of inheritable attributes. Please review that issue for the background and summary of the problem.

## Proposal

Introduce `Fiber#locals` which is a hash table of local attributes which are inherited by child fibers.

```ruby
Fiber.current.locals[:x] = 10

Fiber.new do
  pp Fiber.current.locals[:x] # => 10
end
```

It's possible to reset `Fiber.current.locals`, e.g.

```ruby
def accept_connection(peer)
  Fiber.new(locals: nil) do # This causes a new hash table to be allocated.
    # Generate a new request id for all fibers nested in this one:
    Fiber[:request_id] = SecureRandom.hex(32)
    @app.call(env)
  end.resume
end
```

A high level overview of the proposed changes:

```ruby
class Fiber
  def initialize(..., locals: Fiber.current.locals)
    @locals = locals || Hash.new
  end

  attr_accessor :locals

  def self.[] key
    self.current.locals[key]
  end

  def self.[]= key, value
    self.current.locals[key] = value
  end
end
```

See the pull request <https://github.com/ruby/ruby/pull/6566> for the full proposed implementation.

## Expected Usage

Currently, a lot of libraries use `Thread.current[:x]` which is unexpectedly "fiber local". A common bug shows up when lazy enumerators are used, because it may create an internal fiber. Because `locals` are inherited, code which uses `Fiber[:x]` will not suffer from this problem.

Any program that uses true thread locals for per-request state, can adopt the proposed `Fiber#locals` and get similar behaviour, without breaking on per-fiber servers like Falcon, because Falcon can "reset" `Fiber.current.locals` for each request fiber, while servers like Puma won't have to do that and will retain thread-local behaviour.

Libraries like ActiveRecord can adopt `Fiber#locals` to avoid the need for users to opt into different "IsolatedExecutionState" models, since it can be transparently handled by the web server (see <https://github.com/rails/rails/pull/43596> for more details).

We hope by introducing `Fiber#locals`, we can avoid all the confusion and bugs of the past designs.



-- 
https://bugs.ruby-lang.org/

  parent reply	other threads:[~2022-10-18 12:33 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-16 10:31 [ruby-core:110320] [Ruby master Bug#19062] Introduce `Fiber#locals` for shared inheritable state ioquatix (Samuel Williams)
2022-10-16 22:08 ` [ruby-core:110323] " ioquatix (Samuel Williams)
2022-10-17  7:01 ` [ruby-core:110346] " nobu (Nobuyoshi Nakada)
2022-10-17  7:40 ` [ruby-core:110349] " byroot (Jean Boussier)
2022-10-17  7:50 ` [ruby-core:110350] " ioquatix (Samuel Williams)
2022-10-17  8:23 ` [ruby-core:110352] " byroot (Jean Boussier)
2022-10-17  8:27 ` [ruby-core:110353] " ioquatix (Samuel Williams)
2022-10-17  8:42 ` [ruby-core:110354] " byroot (Jean Boussier)
2022-10-17  9:18 ` [ruby-core:110355] " ioquatix (Samuel Williams)
2022-10-17  9:30 ` [ruby-core:110356] " ioquatix (Samuel Williams)
2022-10-17  9:44 ` [ruby-core:110357] " ioquatix (Samuel Williams)
2022-10-17 10:29 ` [ruby-core:110358] " Eregon (Benoit Daloze)
2022-10-17 10:48 ` [ruby-core:110359] " ioquatix (Samuel Williams)
2022-10-17 10:55 ` [ruby-core:110360] " byroot (Jean Boussier)
2022-10-17 11:12 ` [ruby-core:110361] " ioquatix (Samuel Williams)
2022-10-17 11:48 ` [ruby-core:110362] " byroot (Jean Boussier)
2022-10-17 11:49 ` [ruby-core:110363] " Eregon (Benoit Daloze)
2022-10-17 19:42 ` [ruby-core:110374] " ioquatix (Samuel Williams)
2022-10-17 19:57 ` [ruby-core:110375] " ioquatix (Samuel Williams)
2022-10-17 20:05 ` [ruby-core:110376] " byroot (Jean Boussier)
2022-10-17 21:58 ` [ruby-core:110377] " ioquatix (Samuel Williams)
2022-10-18  8:14 ` [ruby-core:110382] " byroot (Jean Boussier)
2022-10-18 10:15 ` [ruby-core:110389] " ioquatix (Samuel Williams)
2022-10-18 10:37 ` [ruby-core:110391] " byroot (Jean Boussier)
2022-10-18 11:05 ` [ruby-core:110394] " Eregon (Benoit Daloze)
2022-10-18 11:20 ` [ruby-core:110397] " ioquatix (Samuel Williams)
2022-10-18 11:26 ` [ruby-core:110398] [Ruby master Feature#19062] " ioquatix (Samuel Williams)
2022-10-18 11:44 ` [ruby-core:110399] " byroot (Jean Boussier)
2022-10-18 11:55 ` [ruby-core:110400] " ioquatix (Samuel Williams)
2022-10-18 12:06 ` [ruby-core:110405] " byroot (Jean Boussier)
2022-10-18 12:32 ` Eregon (Benoit Daloze) [this message]
2022-10-20  6:48 ` [ruby-core:110433] " matz (Yukihiro Matsumoto)
2022-10-20 12:09 ` [ruby-core:110445] " ioquatix (Samuel Williams)

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.ruby-lang.org/en/community/mailing-lists/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=redmine.journal-99716.20221018123249.3344@ruby-lang.org \
    --to=ruby-core@ruby-lang.org \
    --cc=ruby-core@neon.ruby-lang.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).