{"id":4167,"library":"pebble","title":"Pebble","description":"Pebble is a Python library that enhances `concurrent.futures` with features like timeouts, remote process tracebacks, and cleaner pool management, making threading and multiprocessing more robust and user-friendly. It is currently at version 5.2.0 and maintains an active release cadence with frequent minor updates.","status":"active","version":"5.2.0","language":"en","source_language":"en","source_url":"https://github.com/noxdafox/pebble","tags":["concurrency","multiprocessing","threading","futures","pools","timeouts"],"install":[{"cmd":"pip install pebble","lang":"bash","label":"Install latest version"}],"dependencies":[],"imports":[{"note":"While Pebble extends concurrent.futures, the main classes are exposed directly under the `pebble` namespace for convenience.","wrong":"from pebble.concurrent.futures import ProcessPoolExecutor","symbol":"ProcessPool","correct":"from pebble import ProcessPool"},{"note":"Main classes are exposed directly under the `pebble` namespace. `ThreadPool` is an alias for Pebble's enhanced `ThreadPoolExecutor`.","wrong":"from pebble.concurrent.futures import ThreadPoolExecutor","symbol":"ThreadPool","correct":"from pebble import ThreadPool"}],"quickstart":{"code":"from pebble import ProcessPool\nfrom concurrent.futures import TimeoutError\nimport os\nimport time\n\ndef my_task(data, delay):\n    # Simulate some work\n    time.sleep(delay)\n    return f\"Processed {data} after {delay}s on PID {os.getpid()}\"\n\nif __name__ == \"__main__\": # Essential for ProcessPool on Windows/macOS\n    print(\"--- Pebble ProcessPool Quickstart ---\")\n    with ProcessPool(max_workers=2) as pool:\n        print(\"Submitting tasks...\")\n        # schedule returns a future object, allowing timeout directly on the task\n        future1 = pool.schedule(my_task, args=(\"task A\", 1), timeout=2)\n        future2 = pool.schedule(my_task, args=(\"task B\", 3), timeout=2) # This task will intentionally timeout\n\n        print(\"\\nGetting results for task 1 (should succeed):\")\n        try:\n            result1 = future1.result() # blocks until result is ready or timeout/exception\n            print(f\"Result 1: {result1}\")\n        except TimeoutError:\n            print(\"Task 1 timed out!\")\n        except Exception as e:\n            print(f\"Task 1 raised an unexpected exception: {e}\")\n            # For remote exceptions, e.traceback can provide the remote stack trace\n\n        print(\"\\nGetting results for task 2 (should timeout):\")\n        try:\n            result2 = future2.result()\n            print(f\"Result 2: {result2}\")\n        except TimeoutError:\n            print(\"Task 2 timed out as expected!\")\n        except Exception as e:\n            print(f\"Task 2 raised an unexpected exception: {e}\")\n            # For remote exceptions, e.traceback can provide the remote stack trace\n\n    print(\"\\nAll tasks completed or processed in pool.\")","lang":"python","description":"This quickstart demonstrates how to use Pebble's `ProcessPool` to execute functions in separate processes with built-in timeouts. It covers scheduling tasks, retrieving results, and handling `TimeoutError` as well as other exceptions. The `if __name__ == '__main__':` block is crucial for `ProcessPool` on Windows and macOS."},"warnings":[{"fix":"Always import `TimeoutError` from `concurrent.futures`.","message":"When handling timeouts with `ProcessPool` or `ThreadPool`, the `TimeoutError` exception is from `concurrent.futures`, not directly from `pebble`. Ensure you import it correctly: `from concurrent.futures import TimeoutError`.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Wrap your `ProcessPool` initialization and usage within `if __name__ == '__main__':` block.","message":"When using `ProcessPool`, especially on Windows and macOS, the code that creates the pool must be guarded by `if __name__ == '__main__':`. Failure to do so can lead to `RuntimeError` or infinite recursion when child processes try to re-import the main script.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Prefer `pool.schedule()` over `pool.submit()` to leverage Pebble's extended features, especially for robust error handling and timeouts.","message":"Pebble's `schedule()` method provides direct timeout handling and returns futures that can expose the remote traceback of exceptions via `future.exception().traceback`. If you use `concurrent.futures.submit()`, you won't get these enhanced features.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Review `SIGTERM` handling in child processes if you rely on custom signals. The change was intended to fix issues where explicit signal handling was broken by `Pebble`.","message":"In version 5.1.0, `Pebble` changed its default `SIGTERM` handling to reset it to the default handler for child processes. If you had custom `SIGTERM` handlers in child processes that relied on Pebble not interfering, this behavior might have changed.","severity":"breaking","affected_versions":">=5.1.0"}],"env_vars":null,"last_verified":"2026-04-11T00:00:00.000Z","next_check":"2026-07-10T00:00:00.000Z"}