Repository navigation
Make Semian work in non-main Ractors - #1053
Open
yaroslav-shopify wants to merge 3 commits into
Open
yaroslav-shopify wants to merge 3 commits into
yaroslav-shopify wants to merge 3 commits into
Conversation
Non-main Ractors can't write the Semian module's instance variables,
and can only read the ones that hold shareable values. Semian keeps its
resources, logger and memoized settings there, and its subscribers in a
constant, so the first call into Semian from a non-main Ractor raises,
for example:
Semian#consumers: can not get unshareable values from instance
variables of classes/modules from non-main Ractors (@reset_mutex
from Semian) (Ractor::IsolationError)
Each non-main Ractor now keeps its own resources and consumers in
Ractor-local storage, as each forked process has its own, so its
circuit breakers count its own errors. Bulkheads are still shared
through their SysV semaphores. The main Ractor keeps the module's state
as before, and Semian.reset! only resets the current Ractor's.
- Subscribers: non-main Ractors notify the main Ractor's subscribers
whose names and blocks are shareable, from a frozen copy rebuilt on
each subscribe and unsubscribe. Other blocks capture state that only
the main Ractor can use. Non-main Ractors can subscribe for
themselves too.
- Logger: non-main Ractors use the logger set in the main Ractor if
it's shareable by the time they log. Otherwise they log to their own
$stderr, unless they set a logger of their own.
- Configuration: Semian.namespace= stores a frozen copy of a String,
Semian.thread_safe? no longer memoizes its default, and the
disabled-semaphores warning is issued once in each Ractor.
This needs Ractor.main? and Ractor-local storage, from Ruby 3.4. On
older Rubies, Semian works as before.
Each test failed without the fix, apart from the shareable logger's.
The redis-client test passes the driver as a class, because
RedisClient.driver(:ruby) reads a class instance variable. It also
turns off the bulkhead, because bulkheads in non-main Ractors need the
extension to be marked as Ractor-safe.
The extension implements bulkheads with SysV semaphores, and isn't
marked as Ractor-safe, so on Linux every bulkhead operation in a
non-main Ractor, starting with registering one, raises
Ractor::UnsafeError ("ractor unsafe method called from not main
ractor").
The extension has no mutable global state. Init_semian sets the
exception classes, two IDs and system_max_semaphore_count, and none of
them changes afterwards. Each Semian::Resource only uses its own
struct, which isn't shareable, so it stays in the Ractor that created
it, and its semaphore set, which the kernel synchronizes across
processes, threads and Ractors alike. Keys are SHA-1 digests into a
local buffer.
Each Ractor that registers a resource counts as a worker of its
semaphore set, as each forked process does, so quotas scale with the
number of Ractors. SEM_UNDO adjustments are per process, so a Ractor's
tickets and worker registration are only undone when the process
exits, as for threads.
The test holds a bulkhead's only ticket in the main Ractor and expects
the same resource to time out in a non-main Ractor, registered as a
second worker. It's skipped where semaphores aren't supported, so it
hasn't run on macOS, where this was written.
redis-rb's master requires redis-client 0.30.1, and hiredis-client from redis-client's master now requires 0.31.0, so the gemfile no longer resolves. Use the v0.30.1 tag until redis-rb moves to 0.31.0.
yaroslav-shopify
force-pushed
the
ractorize
branch
from
October 9, 2026 21:10
41a413c to
647e148
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Calling Semian from a non-main Ractor raises
Ractor::IsolationError, and on Linux bulkheads raiseRactor::UnsafeError. Two commits:Tested on macOS with Ruby 3.4, 4.0 and master, so the bulkhead changes will first run in CI.
A third commit pins hiredis-client to redis-client 0.30.1 in
gemfiles/redis_client.gemfile: redis-rb's master requires that version, so the gemfile no longer resolves.