Skip to content

Conversation

@unbalancedparentheses
Copy link

Summary

Unify the separate GenServer implementations (async/tokio and threads) into a single implementation with a Backend enum parameter.

Backend Options

  • Backend::Async - tokio async tasks (default, cooperative multitasking)
  • Backend::Blocking - tokio's blocking thread pool (for blocking I/O)
  • Backend::Thread - dedicated OS thread (for long-running singletons)

Breaking Change

start() now requires a Backend argument:

// Before
let handle = MyServer::new().start();

// After  
let handle = MyServer::new().start(Backend::Async);
// or use default
let handle = MyServer::new().start(Backend::default());

Changes

  • Add Backend enum to lib.rs
  • Modify GenServer to accept Backend parameter
  • Update all examples to use new API
  • Remove thread-based example crates (replaced by Backend::Thread)

~650 lines (mostly deletions of duplicate code)

Test plan

  • All 16 existing tests pass
  • Examples compile and work

🤖 Generated with Claude Code

Consolidate the two separate GenServer implementations (async/tokio and
threads) into a single implementation with a Backend enum parameter.
Breaking change: start() now requires a Backend argument:
- Backend::Async - tokio async tasks (default)
- Backend::Blocking - tokio's blocking thread pool
- Backend::Thread - dedicated OS thread
This provides runtime flexibility without code duplication, allowing
users to mix different execution backends in the same application.
- Add Backend enum to gen_server.rs
- Change start() signature to accept Backend parameter
- Update all examples and tests
- Remove thread-based example crates
type OutMsg: Send + Sized;
type Error: Debug + Send;

fn start(self) -> GenServerHandle<Self> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Backend::Async is default, we can keep start(self) that uses that Backend internally, to avoid the breaking change.

fn start(self) -> GenServerHandle<Self> {
    self.start(Backend::Async)
}

@ElFantasma
Copy link
Collaborator

ElFantasma commented Jan 11, 2026

I think this PR is mostly OK, except for the deletion of the threads examples.

threads behavior is actually not impacted by this PR as it only changes tasks GenServers. See that all tasks GenServers are async, nevertheless the operation mode (default, blocking, on_thread).
threads GenServers, on the opposite are similar but cannot handle async code internally (except if creating a RunTime explicitly inside). These are useful for non async code. E.g. in Ethrex we can take advantage of a threads GenServer to run the Block Processor threads (which don't rely on an async RunTime).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants