Semian for Ruby: Fast Failure and Bulkheads
:monkey: Resiliency toolkit for Ruby for failing fast
At a glance
- What is it?
- Semian is a Ruby library for protecting applications from slow or unresponsive external services with circuit breakers and server-wide bulkheads. It suits services that already handle dependency exceptions but need to stop blocked requests from consuming worker capacity.
- Who is it for?
- Semian fits Ruby services whose dependency failures are primarily slow responses and where predictable concurrency limits or circuit-breaker behavior would reduce cascading failure. It is a poor fit for a dependency that must never be rejected or for an application unable to handle adapter-specific fallback exceptions.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 13 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Semian's target failure: blocked Ruby workers
Semian addresses a specific failure mode that ordinary connection exceptions do not solve by themselves. A refused or reset connection can fail quickly, allowing application code to rescue the driver's base exception. A dependency that accepts work but responds too slowly is more damaging: the Ruby thread remains blocked until the client timeout, and the server loses useful capacity while waiting.
The library is intended for applications making calls to slow or unreliable resources, especially code that already has fallback behavior for connection errors and timeouts. Its stated approach is inspired by Hystrix and Release It. Instead of waiting for a dependency timeout, Semian can reject access immediately by raising an exception that inherits from the underlying driver's base exception class.
That exception relationship is a central design choice. Application code can rescue the normal driver error and catch both native failures and Semian decisions without introducing an unrelated top-level exception hierarchy. Semian does not create a replacement response or retry policy. The final outcome remains an exception, leaving the application responsible for its fallback.
Adapters, circuit breakers, and bulkhead enforcement
Semian does not sit beside a database or HTTP client as a separate proxy. It is loaded through resource adapters that monkey-patch supported drivers. The listed adapters cover `semian/mysql2`, `semian/redis`, `semian/net_http`, `semian/activerecord_trilogy_adapter`, `semian/activerecord_postgresql_adapter`, and `semian-postgres`.
Each resource is checked when access is requested. The circuit breaker limits requests to a dependency that is having trouble. Bulkheading controls concurrent access to one resource. The README states that access is coordinated server-wide with SysV semaphores, which means this concurrency control spans the relevant process environment rather than being limited to a single Ruby object.
A custom adapter has a defined integration contract. It includes `Semian::Adapter`, returns a stable `semian_identifier`, wraps the driver's connection or query method with `Semian::Resource#acquire`, and defines `ResourceBusyError` and `CircuitOpenError`. The identifier must distinguish each logical resource, such as a named Redis master or MySQL shard. The errors should inherit from the raw driver's base exception class.
These requirements also expose a thread-safety boundary. Adapter state is intended for an object representing one resource, typically one connection. Assigning the same identifier to unrelated resources would merge their circuit-breaker or bulkhead identity. Adapter authors need to wrap access at the lowest suitable level rather than adding checks only around high-level application methods.
Gemfile installation and first adapter load
The README recommends declaring the gem and its required adapters in the `Gemfile`. This loads each adapter early during application boot, which the documentation presents as protection for the boot process. The exact declaration shown is:
gem 'semian', require: %w(semian semian/mysql2 semian/redis)Use only the adapters required by the service. This example enables both the MySQL2 and Redis integrations, while the repository also contains a `net_http` adapter and Active Record or PostgreSQL adapters listed above. The first practical step after the application loads these files is to pass a `semian` configuration when initializing each supported client.
The documented MySQL2 form begins with a client initialization and a configuration containing at least a resource name and ticket count:
client = Mysql2::Client.new(host: "localhost", username: "root", semian: {
name: "master",
tickets: 8
})The repository also provides `examples/net_http/`, `examples/colors.rb`, and `examples/dual_circuit_breaker_demo.rb`, but the README does not document exact commands for those examples. The file names alone are not enough to prescribe an invocation. In an application, the first observable check is whether a configured client call can reach its dependency normally or whether Semian raises the adapter's inherited busy or open-circuit exception when the resource is unavailable.
LRU retention and validation controls in Semian
Semian maintains resource state in an LRU cache, and the README documents three global controls. `maximum_lru_size` caps cache size under the normal default of 500. Setting it to `0` enables aggressive garbage collection. `minimum_lru_time` controls how recently a resource must have been updated before it can be collected, with a default of 300 seconds. `default_force_config_validation` controls whether validation or constraint failures raise exceptions or are logged.
The cache settings interact. The documentation says `minimum_lru_time` is the stronger guarantee: a recently updated resource remains resident even when retaining it pushes the cache beyond `maximum_lru_size`. This prevents churn for active resources at the cost of allowing temporary cache growth.
The following exact settings demonstrate aggressive collection, a 60-second minimum residence time, and explicit validation failures:
Semian.maximum_lru_size = 0
Semian.minimum_lru_time = 60
Semian.default_force_config_validation = trueThe README warns that `default_force_config_validation = true` can be breaking because misconfigured Semian instances will raise errors. That behavior is useful for surfacing configuration mistakes, but it changes boot or resource initialization from a logged defect into an exception. Operators need to review every adapter's identifier, ticket setting, and success or failure configuration before enabling it.
Operational boundaries of the SysV bulkhead
The bulkhead is the clearest infrastructure constraint in Semian. It uses SysV semaphores for server-wide coordination, so an environment that does not provide compatible SysV semaphore behavior is not a complete deployment target for that feature. The README does not document a portable fallback for coordinating bulkheads across hosts.
Bulkhead limits are also not generic thread-pool controls. They apply to a named resource and reject access when it has no remaining tickets, producing `ResourceBusyError` through the adapter. The configuration shown uses `tickets: 8`, but the README does not give a universal formula for choosing that number. An adoption decision must account for the concurrency that one logical resource can tolerate and the fallback available when the limit is reached.
Circuit breakers add another source of state. Their thresholds affect when requests begin being rejected, while the cache controls govern how long resource state remains resident. The README does not present a single dashboard, persistence mechanism, or externally managed configuration service. This is a code-level Ruby library whose behavior is embedded through driver adapters, not an independent resilience service.
Toxiproxy tests conditions that Semian does not inject
Toxiproxy is the clearest alternative described by the README, although the two address different layers. Semian runs in the Ruby application and intercepts resource access through adapters. Toxiproxy is presented as the other component in a Ruby resiliency kit and is used to write automated resiliency tests.
The practical difference is control over failure injection. Semian can reject access according to circuit-breaker and bulkhead state, but it is not documented as a tool that creates arbitrary network latency for a test. A test can then exercise application behavior around a slow or failed resource while Semian supplies runtime admission controls.
Neither component replaces the other in the documented setup. Semian provides runtime patterns for slow external resources. Toxiproxy is used to write automated resiliency tests. For simple dependency failures, an application can still use ordinary exception handling and timeouts, but that path does not add Semian's circuit breaker or SysV-coordinated concurrency limit.
MIT licensing, releases, and Semian maintenance state
Semian uses the MIT license. Its repository is not archived, and the recorded last push was on 2026-10-09. The release list includes `v0.27.1` dated 2026-02-09, `v0.27.0` dated 2026-01-28, and `v0.26.6` dated 2025-10-21. These dates show recent repository activity and published version changes, but the README does not promise a particular support period or compatibility policy.
The MIT license permits use, modification, distribution, and sublicensing under its conditions, including preservation of copyright and license notices. This is a statement about the documented license, not legal advice. Organizations should still review their own distribution, notice, and dependency policies.
Upgrading involves attention to adapter compatibility as well as Semian itself. The README lists public driver versions for MySQL2 and Redis as approximately `~> 0.3.16` and `~> 3.2.1`, respectively. It also warns that strict configuration validation can turn previously logged misconfigurations into exceptions. For that reason, a release change should be reviewed against the selected adapter, resource identifiers, ticket settings, and fallback rescues.
Editorial conclusion
Semian fits Ruby services whose dependency failures are primarily slow responses and where predictable concurrency limits or circuit-breaker behavior would reduce cascading failure. It is a poor fit for a dependency that must never be rejected or for an application unable to handle adapter-specific fallback exceptions. Before adoption, verify that each driver can report the intended success and failure signals, assign resource identifiers that will remain unique, and confirm that the operating environment supports the SysV semaphore requirement for server-wide bulkheads.
Frequently asked questions
What problem does Shopify Semian solve in Ruby applications?
It prevents slow or unresponsive dependencies from occupying Ruby workers until their timeouts. Circuit breakers and bulkheads can reject access immediately with exceptions that existing driver rescue paths can handle.
How do you install and configure Semian?
Add `gem 'semian'` to the Gemfile and require the adapters for the drivers in use. Pass a `semian` configuration when initializing each supported client, including a unique resource name and relevant circuit-breaker or bulkhead settings.
Does Semian require Toxiproxy to protect a Ruby service?
No. Toxiproxy is described as a companion for automated resiliency tests, while Semian performs runtime protection through circuit breakers and bulkheads. The deployment environment must support SysV semaphores if server-wide bulkheads are used.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/shopify-semian)Was this useful?