Hello, everyone!
I just released gearmand 2.2.0 on GitHub.
https://github.com/gearman/gearmand/releases/tag/2.2.0
**gearmand 2.2.0** is a feature and bug-fix release with no breaking changes to the core protocol or default client/server behavior. It adds an opt-in consistent-hash (ketama) server selection mode for libgearman clients, improves reliability of job submission and status handling, fixes several long-standing crashes and hangs, and tightens packaging and CI.
### Notable Behavior Change
**"show unique jobs" admin output format** (PR #527 by @p-alik) – Each line is now `<job handle>\t<unique>` instead of just `<unique>`. The handle is placed first because it never contains a tab (a unique ID may). Scripts that previously treated the entire line as the unique ID must now take the text after the first tab. This makes it possible to map a known unique ID to the handle expected by "cancel job" and matches the layout of "show jobs".
### Major New Features / Improvements
- **Opt-in ketama hash-based server selection by job unique** (PR #511 by @p-alik):
- New client APIs `gearman_client_set_server_selection_by_unique()` / `gearman_client_server_selection_by_unique()` and the `GEARMAN_CLIENT_SERVER_SELECTION_BY_UNIQUE` option flag.
- When enabled, job-submission commands route to a server chosen by hashing the job's unique ID against a ketama consistent-hash ring built from the client's current connection list, with fail-over to the next server in ring order.
- Disabled by default; status and other non-submission commands are unaffected. Existing order-based selection is preserved unless the caller opts in.
- Empty unique falls back to the default selection path.
- The setting is preserved across `gearman_client_clone()`.
- Comprehensive unit and multi-server integration tests (including fail-over and distribution checks).
- Library version bumped to 9:0:1 (soname remains `libgearman.so.8`).
- Man pages and documentation added/shipped.
- Fixes long-standing issue #64.
### Notable Bug Fixes
- **Fixed client hang after `GET_STATUS_UNIQUE` / unique status followed by background job submission** (PRs #521 by @killerbishop / Patrick O'Lone, #522 and #523 by @p-alik; fixes issue #520):
- `GEARMAN_COMMAND_GET_STATUS_UNIQUE` (and related status paths) no longer incorrectly advance `created_id`.
- Introduced `gearman_command_expects_job_created()` so only true job-submission commands allocate and match `JOB_CREATED` slots.
- ERROR handler and send-failure paths no longer leave `created_id` ahead of `created_id_next`.
- Regression tests added (including a stub server that answers `GET_STATUS_UNIQUE` with ERROR).
- **Fixed HTTP protocol plugin abort / corruption on job completion with empty or WORK_DATA content** (PR related commits by @p-alik; fixes issue #516):
- `HTTPtext::pack()` no longer indexes an empty content buffer (which aborted under `_GLIBCXX_ASSERTIONS`).
- WORK_DATA payload is now appended after the HTTP header instead of overwriting it; Content-Length accounts for the full body; last-byte truncation of WORK_DATA chunks is fixed.
- `t/httpd` is now run by `make check` with an exact body assertion.
- **Fixed dangling `_recv_packet` alias on `receiving()` error paths** (PR #510 by @p-alik; fixes issue #368):
- Terminal errors (timeout mid-packet, unpack/malloc failures, READ_DATA failures) now clear the non-owning alias so later `close_socket()` / teardown does not free already-freed memory.
- **Fixed hang / self-looped job list after `CAN_DO_TIMEOUT` with fast job completion** (by @p-alik; fixes issue #119):
- `gearman_server_job_free()` now cancels any pending per-connection job timeout when freeing a job that was still assigned to a worker, preventing the stale timer from operating on a recycled job structure.
- **Surface real `connect()` failure reason on address exhaustion** (by @p-alik; fixes issue #505):
- The final "Connection to host:port failed" message now includes `strerror()` of the last failed attempt (e.g. ECONNREFUSED) instead of a generic string.
- **Preserve the first real failure across `gearman_universal_st::flush()`** (by @p-alik; fixes issue #513):
- Later connections in the flush loop can no longer overwrite an earlier useful error message (e.g. a specific `GEARMAN_COULD_NOT_CONNECT`) with a later generic or `GEARMAN_IO_WAIT` result.
- **Compile-time coverage of the command table** (by @p-alik and @esabol):
- `gearmand_command_info_list[]` is now sized by its initializer with a `static_assert` that the row count equals `GEARMAN_COMMAND_MAX`.
- Additional checks verify each entry's code and argc match expectations.
- `gearman_strcommand()` / `gearman_enum_strcommand()` now bound lookups by `GEARMAN_COMMAND_MAX`.
### Build / CI / Maintenance
- Added missing libgearman protocol tests (PR #524 by @esabol).
- Ensured `libgearman/server_selection.hpp` is included in the release tarball (PR #528 by @esabol).
- Added CI test that generates a distribution tarball and then builds it (PR #529 by @esabol).
- Added the man pages for the new server-selection functions to the distribution tarball (PR #530 by @p-alik).
- CI workflow cleanups: fixed g++ version for ubuntu-22.04 test, removed superfluous `CXXFLAGS` settings (multiple commits by @esabol).
- Updated `.dockerignore` files (by @esabol).
### Contributors
Huge thanks to everyone who contributed to this release, notably:
- **Alexei Pastuchov (@p-alik)** — ketama server selection by unique hash, the majority of the reliability and hang/crash fixes, command-table hardening, tests, and documentation
- **Ed Sabol (@esabol)** — packaging/tarball completeness, protocol test improvements, CI improvements, PR reviews and merging
- **Patrick O'Lone (@killerbishop)** — initial fix for `GET_STATUS_UNIQUE` incorrectly advancing `created_id` (PR #521)
**Full Changelog**:
https://github.com/gearman/gearmand/compare/2.1.0...2.2.0