Files
oslo.service/releasenotes/notes/add-threading-backend-9b0e601e5c1282e1.yaml
Daniel Bengtsson 5de514f1f8 Add threading backend implementation using cotyledon and standard threads
Introduces a new threading backend for oslo.service that provides a
complete alternative to the eventlet-based backend.

This backend includes:
	• A ThreadGroup and Thread implementation using the Python
	  threading module.
	• A reimplementation of all looping call utilities (
	  FixedIntervalLoopingCall, DynamicLoopingCall, etc.) using
	  threading.Event and futurist.ThreadPoolExecutor.
	• A service management layer based on cotyledon, including
	  Service,ServiceWrapper, Launcher, and ProcessLauncher.
	• A new ThreadingBackend class that exposes all components
	  needed for integration into oslo.service.

This change provides a robust and eventlet-free alternative backend while maintaining API compatibility.

Change-Id: Ia7518401ccdcc28afbffd4ffe5c3b772f3617001
2025-05-14 14:03:04 +02:00

65 lines
2.8 KiB
YAML

features:
- |
Added a new `threading` backend to `oslo.service`, using standard Python
threads instead of `eventlet`. This includes a full implementation of:
- `Service`, `Launcher`, `ServiceLauncher`, and `ProcessLauncher` using
`cotyledon`
- `LoopingCall` variants (`FixedIntervalLoopingCall`,
`DynamicLoopingCall`, etc.) using `futurist.ThreadPoolExecutor`
- A new `ThreadGroup` and `Thread` abstraction to mimic `eventlet`-like
behavior
- A native `SignalHandler` implementation using standard Python signals
This backend provides a standard-thread-compatible alternative that avoids
monkey-patching, making it suitable for environments where `eventlet` is
problematic or undesirable.
Additionally:
- `ProcessLauncher` now supports a `no_fork=True` mode, allowing services
to run in the main process without forking. This is useful when `fork()`
is unsafe — for example, in threaded environments or with Python 3.12+
where the default multiprocessing start method has changed to `spawn`.
- A new `register_backend_default_hook()` API has been added. It allows
users to define a fallback backend type in case `init_backend()` was not
called early enough. This is helpful in environments where import order
or initialization timing cannot be guaranteed.
Example:
```python
from oslo_service import backend
backend.register_backend_default_hook(lambda: backend.BackendType.THREADING)
```
This hook will only be used if `init_backend()` has not already been called.
upgrade:
- |
While Python 3.14 defaults to ``spawn`` as the multiprocessing start
method, `oslo.service` continues to rely on ``fork`` as the only supported
method for creating worker processes. Many parts of OpenStack depend on
objects that cannot be safely pickled (e.g. argparse parsers, thread locks,
lambdas in config defaults), which makes ``spawn`` currently impractical.
In the long term, process scaling should be handled externally (e.g. via
Kubernetes or systemd), rather than by the service itself.
issues:
- |
When using the `threading` backend with multiple workers
(i.e. `ProcessLauncher` with `fork()`), **starting threads before the fork
occurs can lead to corrupted state** due to how `os.fork()` behaves in
multi-threaded processes. This is a known limitation in Python.
See: https://gibizer.github.io/posts/Eventlet-Removal-The-First-Threading-Bug/#threads--osfork--confused-threadpools
To avoid this issue, you can:
- Ensure that no threads are started before `oslo.service` forks the workers.
- Use `ProcessLauncher(no_fork=True)` to disable forking entirely.
- Explicitly manage thread lifecycle — for example, stop all threads before
forking, as currently done in Nova.