Skip to content

Add Elasticsearch 9.x support#1009

Open
mattmenefee wants to merge 3 commits intotoptal:masterfrom
mattmenefee:elasticsearch-9-support
Open

Add Elasticsearch 9.x support#1009
mattmenefee wants to merge 3 commits intotoptal:masterfrom
mattmenefee:elasticsearch-9-support

Conversation

@mattmenefee
Copy link
Contributor

@mattmenefee mattmenefee commented Mar 17, 2026

Note: This PR depends on #1008 (CI and test infrastructure improvements) and #1010 (migration guide and doc fixes) which should be merged first.

Summary

  • Widen elasticsearch gem dependency from < 9.0 to < 10.0 to support ES 9.x clusters
  • Restructure scroll API calls to nest scroll_id under body:, matching the elasticsearch-ruby 9.x client interface
  • Use .body accessor on cat.indices response for ES 9.x gem compatibility
  • Remove all references to _type: mock response helpers (Chewy::Minitest::Helpers and Chewy::Rspec::Helpers), EVERFIELDS, Index::Wrapper accessors, and README examples
  • Remove obsolete _parent from EVERFIELDS
  • Pin elasticsearch gem to ~> 8.14 in CI for ES 8.x matrix entries (the 9.x gem sends a compatible-with=9 header that ES 8.x rejects)
  • Add Ruby 3.4 / Rails 8.0 / ES 8.15.0 CI matrix entry
  • Expand migration guide with code examples, gem pinning guidance, and corrected URLs
  • Add ES version matrix to CI (9.3.1 default, 8.15.0 spot-checks)
  • Bump version to 9.0.0

Breaking changes

  • The search_query.chewy notification payload for scroll requests now nests scroll_id under body: (i.e. {scroll: '1m', body: {scroll_id: '...'}} instead of {scroll: '1m', scroll_id: '...'}). Update any application code that subscribes to scroll notification payloads.
  • '_type' => '_doc' has been removed from mock response helpers in Chewy::Minitest::Helpers and Chewy::Rspec::Helpers. Remove any test assertions expecting _type in mock responses.

Test plan

  • Verify all existing specs pass against ES 8.15.0
  • Verify all existing specs pass against ES 9.3.1
  • Verify scroll pagination works end-to-end on both ES versions
  • Verify search_query.chewy notification payload matches new format
  • Confirm mock_elasticsearch_response helpers produce valid responses without _type

@mattmenefee mattmenefee force-pushed the elasticsearch-9-support branch from e9bc5d7 to dbd4a3a Compare March 17, 2026 17:53
@mattmenefee
Copy link
Contributor Author

mattmenefee commented Mar 17, 2026

Note: This PR depends on #1008 (CI and test infrastructure improvements) and #1010 (migration guide and doc fixes) which should be merged first. Once those are merged, I'll rebase this branch to resolve any conflicts.

@mattmenefee mattmenefee force-pushed the elasticsearch-9-support branch from dbd4a3a to 210c1f9 Compare March 17, 2026 20:52
@mattmenefee mattmenefee marked this pull request as ready for review March 17, 2026 20:53
@mattmenefee mattmenefee requested a review from a team as a code owner March 17, 2026 20:53
@mattmenefee mattmenefee force-pushed the elasticsearch-9-support branch 2 times, most recently from c09dd71 to 98955eb Compare March 17, 2026 23:23
Copy link
Member

@bbatsov bbatsov left a comment

Choose a reason for hiding this comment

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

Thanks for tackling ES 9 support! We'll review this properly after #1008 and #1010 have been updated and merged, since this builds on top of both.

One thing I'd suggest splitting out now: the Sidekiq testing API changes (require 'sidekiq/testing' -> Sidekiq.testing!(:fake), Sidekiq::Testing.inline! -> Sidekiq.testing!(:inline)) are unrelated to ES 9 and would be easier to review and merge as a separate PR.

The previous implementation parsed the text-format `cat.indices`
response by splitting on whitespace and taking column index [2].
This is brittle — column order can change between ES versions.

Switch to `format: 'json'` and extract the `index` key from each
entry. Also filter out system indices (prefixed with '.') to avoid
deleting ES-internal indices like .security or .kibana.
The previous CI setup launched ES via `docker compose up` with a
`sleep 15` wait, which was fragile and slow. Promote ES to a proper
GitHub Actions `services:` block with a built-in health check
(`wait_for_status=yellow`) for reliable startup detection.

- Add `concurrency` group to cancel in-progress runs on PR updates
- Add `timeout-minutes` to both jobs (15 test, 10 rubocop)
- Add `permissions: contents: read` for least-privilege
- Rename test job from `ruby-3` to `test` (Ruby 4.0 is in the matrix)
- Switch docker-compose image to `docker.elastic.co` registry and
  parameterize the version via `ES_VERSION` env var
Elasticsearch 9.x introduced breaking changes to the elasticsearch-ruby
client gem that prevent Chewy from working with ES 9 clusters:

1. The scroll API now requires scroll_id nested under a body: key
   ({scroll: '1m', body: {scroll_id: '...'}}) rather than as a
   top-level parameter. Without this, scroll requests raise an
   ArgumentError in elasticsearch-ruby 9.x.

2. API responses are now wrapped in Elasticsearch::API::Response objects
   instead of returning raw hashes/arrays. Code that calls .map or
   other Enumerable methods directly on responses (e.g. cat.indices)
   must now call .body first to access the underlying data.

3. The '_type' field was removed from search responses in ES 7+ and
   the elasticsearch-ruby 9.x client no longer includes it. All
   references to '_type' have been removed: mock response helpers,
   EVERFIELDS, wrapper accessors, and documentation examples.

4. The elasticsearch Ruby gem at version 9.x sends a compatible-with=9
   header that ES 8.x servers reject. CI matrix entries that test
   against ES 8.x must pin the gem to ~> 8.14.

Changes:

- Widen elasticsearch gem dependency from < 9.0 to < 10.0
- Restructure perform_scroll to nest scroll_id under body:, which is
  compatible with both elasticsearch-ruby 8.x and 9.x
- Access .body on cat.indices response in the drop_indices test helper
- Remove '_type' from Minitest and RSpec mock response helpers,
  EVERFIELDS, Index::Wrapper accessors, and README examples
- Remove obsolete '_parent' from EVERFIELDS
- Add elasticsearch version matrix to CI (9.3.1 default with 8.15.0
  spot-checks) using dynamic service container images
- Pin elasticsearch gem to ~> 8.14 in CI for ES 8.x matrix entries
- Add Ruby 3.4 / Rails 8.0 / ES 8.15.0 CI matrix entry
- Add scroll body format assertion in scrolling specs
- Expand migration guide with code examples, gem pinning guidance,
  corrected URLs, and more detailed upgrade steps
- Consolidate CHANGELOG entries into single item with sub-bullets
- Default docker-compose ES image to 9.3.1
- Bump version to 9.0.0
@mattmenefee mattmenefee force-pushed the elasticsearch-9-support branch from 98955eb to c87f74d Compare March 18, 2026 16:30
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