- Python 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| docker | ||
| src | ||
| .gitignore | ||
| MANIFEST.in | ||
| pyproject.toml | ||
| README.md | ||
splent_feature_elasticsearch
Reusable Elasticsearch infrastructure for SPLENT products (service archetype).
Ships a single-node Elasticsearch 8.x container and a generic, domain-agnostic
ElasticsearchService that any feature can consume through the service locator.
What it provides
ElasticsearchService(registered in the service locator):available(),index_name(name),ensure_index(name, mappings=None),index_document(index, id, body),bulk_index(index, documents),delete_document(index, id),refresh_index(name),search(index, query_body),delete_index(name),health().- Docker:
docker/docker-compose.dev.yml(host port published) anddocker/docker-compose.prod.yml(internal-only onsplent_network), both with a healthcheck and a namedelasticsearch_datavolume. - CLI:
splent feature:elasticsearch status.
One node, many products
In development the CLI starts each feature as its own compose project, named
after the feature reference with no product name in it. Every product in the
workspace therefore talks to the same Elasticsearch container and writes into
the same data volume. Index names are a flat, node-wide namespace, so two
products that both index pages would overwrite each other's documents and
answer searches with each other's material.
Every index name handed to the service is prefixed with
ELASTICSEARCH_INDEX_PREFIX, whose shipped value __PRODUCT__ is resolved to
the product name by product:env --merge and product:build. A feature keeps
using its own short name and never has to know.
es.ensure_index("pages") # creates innosoft_app_pages
es.index_name("pages") # "innosoft_app_pages"
splent feature:elasticsearch status prints the namespace in use, which is the
quickest way to check that a product is not sharing indices with its neighbour.
An index is a cache and never the authority on visibility. This service stores and returns whatever documents it is given; whether a particular reader may see a particular hit is decided at request time by the feature that owns the material.
Graceful degradation and typed errors
Elasticsearch is a soft dependency. available() never raises, and every other
operation raises ElasticsearchError, never a raw client exception. Two
subclasses say what happened and what to do about it.
| Exception | Meaning | Usual response |
|---|---|---|
ElasticsearchUnavailable |
Disabled, or the node could not be reached. | Fall back to a slower search. |
ElasticsearchRequestError |
The node answered and refused the request (malformed query, rejected mapping, missing permission). | Let it surface. Retrying will not help. |
from splent_framework.services.service_locator import service_proxy
from splent_io.splent_feature_elasticsearch.services import ElasticsearchUnavailable
es = service_proxy("ElasticsearchService")
try:
results = es.search("posts", {"query": {"match": {"title": query}}})
except ElasticsearchUnavailable:
results = fallback_sql_search(query)
Bulk indexing
A full reindex is thousands of documents, and one HTTP round trip each turns a
maintenance command into something nobody runs. bulk_index consumes any
iterable lazily, sends batches through the _bulk API and reports what
happened, so a single bad document does not cost you the other 9999.
report = es.bulk_index(
"pages",
({"id": page.id, "body": {"title": page.title, "body": page.text}} for page in pages),
)
es.refresh_index("pages")
# {"indexed": 9999, "failed": 1, "errors": [{"id": 42, "error": "..."}]}
Only a failure of the request itself raises. Per-document failures come back in the report, with the error list capped so a broken mapping cannot flood a log.
Configuration
| Env var | Default | Purpose |
|---|---|---|
ELASTICSEARCH_URL |
http://localhost:9200 |
Node URL. The Docker .env sets http://splent_feature_elasticsearch:9200 for container-to-container access. |
ELASTICSEARCH_ENABLED |
true |
Feature kill switch. When false all operations degrade immediately. |
ELASTICSEARCH_INDEX_PREFIX |
splent |
Namespace for this product's indices. The Docker .env ships __PRODUCT__, resolved to the product name. |
ELASTICSEARCH_HOST_PORT |
9201 |
Host port published in development only. |
ELASTICSEARCH_JAVA_OPTS |
-Xms512m -Xmx512m |
Heap for the node, read by the production compose file. |
Tests
splent feature:test splent_feature_elasticsearch
Unit tests mock the client boundary, so no network access is required.