Skip to content

fix: add opensearch compatibility guardrails - #51

Merged
egdbear merged 1 commit into
mainfrom
egdbear/opensearch-compatibility
Jun 11, 2026
Merged

egdbear merged 1 commit into
mainfrom
egdbear/opensearch-compatibility

Conversation

@egdbear

@egdbear egdbear commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Description

Our OpenSearch cluster is now on v3, but estella's compatibility with it depends entirely on consuming apps pinning the right client version themselves. Three changes to lock in what production already relies on:

  1. Pin the transitive elasticsearch client to < 7.14 in the gemspec. Clients 7.14+ run a product check that refuses to connect to OpenSearch (elastic/elasticsearch-ruby#1429). Gravity already carries this pin in its own Gemfile; this moves it upstream so no consumer can resolve a broken client via bundle update or a missing pin. With it, bundler locks elasticsearch 7.13.3 alongside elasticsearch-model 7.2.1.

  2. Fix an operator-precedence bug in DEFAULT_SETTINGS (lib/estella/analysis.rb). defined? Rails && Rails.env == 'test' parses as defined?((Rails && ...)), which is always truthy, even when Rails isn't loaded. The "test-only" number_of_shards: 1, number_of_replicas: 1 settings were therefore applied in every environment, including production. Now they only apply in a Rails test env.

  3. Run CI against OpenSearch. The test now covers Elasticsearch 7.17.18 (unchanged), OpenSearch 2.19.1, and OpenSearch 3.3.0 (our live), so CI tests against what production actually runs. If a future OpenSearch version breaks the pinned client, the build goes red instead of production.

Context

OpenSearch 3 removed compatibility.override_main_response_version (opensearch#18228), so there is no server-side compatibility fallback anymore: everything rests on the client staying below 7.14. That client (7.13.3) is end-of-life, which is fine as a stopgap but not a destination.

Note: the two OpenSearch CI jobs are new, so this PR's build is the first real evidence of whether the suite passes against 2.x and 3.x.

Heads-up for consumers

The settings fix changes behavior for models calling bare searchable do ... end without explicit settings outside of tests: new indices get cluster defaults instead of a forced 1 shard / 1 replica. OpenSearch defaults are also 1/1, so nothing changes in practice unless cluster-level index templates say otherwise. In Gravity, all searchable models pass explicit settings except Video, which deserves a small follow-up.

Next steps: estella 8.0 on opensearch-ruby or different approach TBD

Slack context here.

The real fix is dropping elasticsearch-model and elasticsearch entirely and rebuilding estella's thin integration layer on opensearch-ruby, released as estella 8.0. The surface estella actually uses from elasticsearch-model is small: index_name storage, the settings/mapping capture, import, the client proxy, and the hits-to-records loader. That's a few hundred lines to reimplement.

Gravity already has opensearch-ruby 3.4.0 for its recommendation and duplicate-detection services, so 8.0 would consolidate two client stacks into one that's already proven in production. It's also the right moment to add alias support (create-with-alias, swap-based reindexing): Gravity's indices are now aliased on the cluster, which breaks reload_index! — see #48 for an earlier attempt at a partial fix. Since the index lifecycle methods get rewritten in 8.0 anyway, that's where the complete fix belongs.

@egdbear egdbear self-assigned this Jun 10, 2026
narikazu
narikazu previously approved these changes Jun 10, 2026
Comment thread .circleci/config.yml Outdated
ruby_version: ["3.1"]
search_image:
- "docker.elastic.co/elasticsearch/elasticsearch:7.17.18"
- "opensearchproject/opensearch:2.19.1"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

question: do we need to maintain the gem on opensearch v2.19.1? We only have v3.3.0, so I think we don't need to support it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good spot! Not at all!

@narikazu

Copy link
Copy Markdown
Member

The real fix is dropping elasticsearch-model and elasticsearch entirely and rebuilding estella's thin integration layer on opensearch-ruby, released as estella 8.0. The surface estella actually uses from elasticsearch-model is small

Have we decided to keep maintaining Estella with OpenSearch? I think there's another option worth considering: moving new code into Gravity rather than modifying Estella. Since the gem is just a thin wrapper around ES/OS, that should be achievable.

@egdbear
egdbear force-pushed the egdbear/opensearch-compatibility branch from 95b0d87 to 68cf19d Compare June 10, 2026 11:08
@egdbear

egdbear commented Jun 10, 2026

Copy link
Copy Markdown
Contributor Author

Have we decided to keep maintaining Estella with OpenSearch? I think there's another option worth considering: moving new code into Gravity rather than modifying Estella. Since the gem is just a thin wrapper around ES/OS, that should be achievable.

Thanks for bringing this up 🙏 @narikazu

Yeah, I wasn't sure whether we'd want another repo (Ostella) or even a small wrapper around Gravity. This seemed like the simplest and most common approach, which is why I included it as an option. Thanks for calling it out!

@narikazu
narikazu self-requested a review June 10, 2026 11:14
Comment thread .circleci/config.yml
ruby_version: ["3.1"]
search_image:
- "docker.elastic.co/elasticsearch/elasticsearch:7.17.18"
- "opensearchproject/opensearch:3.3.0"

@mc-jones mc-jones Jun 10, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not clear on how this is working. Does the circle image key take an array and then just run the test
suite against each of the passed in images?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Exactly. The matrix key generates the cross-product of all parameter values and produces one independent job per combination. search_image is interpolated into the docker: services list at the top of the job:

docker:
      - image: "cimg/ruby:<< parameters.ruby_version >>"
      - image: "<< parameters.search_image >>"   #  the engine under test

So each generated job boots a different search engine as the second service container, all reachable on localhost:9200.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Neat. Didn't know about that feature.

@mzikherman mzikherman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nice! As long as we keep using estella this makes sense, but also agree it might be worth deciding on the future of estella and if it's worth having it be separate from Gravity or not.

@leamotta leamotta left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nice one! 🔒

@egdbear
egdbear merged commit c39a42e into main Jun 11, 2026
3 checks passed
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.

5 participants