Transport classes and utilities shared among .NET Elastic client libraries
This library was lifted from elasticsearch-net and then transformed to be used across all Elastic services rather than only Elasticsearch.
Provides the clients connectivity components, exposes a (potentially) cluster aware request pipeline that can be resilient to nodes dropping in & out of rotation.
This package is heavily optimized for the Elastic (elastic.co) product suite and Elastic Cloud (cloud.elastic.co) SAAS offering.
The transport is designed to fail over fast and in constant time.
If a Node is considered bad it will fail-over only immediately given the overall request timeout allows for it.
It's an explicit non-goal to introduce full (incremental) retry mechanisms. This library is too generic to be making
these decisions and should be pushed on to the products/libraries making use of Elastic.Transport
This library can be used on its own but is typically used as the heart of a facade client that models all the API endpoints.
In its most direct and terse form you can use the following to create requests.
var settings = new TransportConfiguration(new Uri("http://localhost:9200"));
var transport = new Transport(settings);
var response = transport.Get<StringResponse>("/");
var headResponse = transport.Head("/");Get and Head are extension methods to the only method HttpTransport dictates namely Request() and its async variant.
Wrapping clients most likely will list out all components explicitly and use Transport<TConfiguration>
var pool = new StaticConnectionPool(new[] {new Node(new Uri("http://localhost:9200"))});
var connection = new HttpConnection();
var serializer = LowLevelRequestResponseSerializer.Instance;
var product = ElasticsearchProductRegistration.Default;
var settings = new TransportConfiguration(pool, connection, serializer, product);
var transport = new Transport<TransportConfiguration>(settings);
var response = transport.Request<StringResponse>(HttpMethod.GET, "/");This allows implementers to extend TransportConfiguration with product/service specific configuration.
HttpTransport itself only defines Request() and RequestAsync() and all wrapping clients accept an HttpTransport.
The HttpTransport implementation that this library ships models a request pipeline that can deal with a large variety of topologies
Whilst complex every effort is made to only walk paths if we are certain they provide value.
It introduces two special API calls
sniffa request to the service/product that should inform the client about the active topology.pingthe fastest request the transport can do to validate aNodeis alive.
If you instantiate Transport you can pass an instance of IProductRegistation to provide implementations
for sniff and ping.
var settings = new TransportConfiguration(new Uri("http://localhost:9200"));
var transport = new Transport(settings);Will use the DefaultProductRegistration wich opts out of sniff and ping
However this library ship with a default implementation to fill in the blanks for Elasticsearch
so we can create a transport for Elasticsearch that support sniff and ping as followed
var uri = new Uri("http://localhost:9200");
var settings = new TransportConfiguration(uri, ElasticsearchProductRegistration.Default);
var transport = new Transport(settings);All components are optional and ship with sane defaults. Typically client users only provide
the IConnectionPool to the transport configuration
IConnectionPoola registry ofNodesthe transport will ask for a view it can iterate over.
ONLY if a connection pool indicates it supports receiving new nodes will the transport sniff.IConnection
Abstraction for the actual IO the transport needs to perform.HttpTransportSerializer
Allows you to inject your own serializer, the default usesSystem.Text.JsonIProductRegistration
Product specific implementations and metadata provider
ITransportConfigurationValues
A transport configuration instance, explictly designed for clients to introduce subclasses ofRequestPipelineFactoryA factory creatingRequestPipelineinstancesDateTimeProviderAbstraction around the staticDateTime.Nowso we can test algorithms without waiting on the clock on the wall.MemoryStreamFactoryA factory creatingMemoryStreaminstances.
The default HttpTransport implementation ships with various DiagnosticSources to make the whole
flow through the request pipeline auditable and debuggable.
Every response returned by Transport has to implement TransportResponse which has one property ApiCall of
type ApiCallDetails which in turns holds all information relevant to the request and response.
NOTE: it also exposes response.ApiCallDetails.DebugInformation always holds a human readable string to indicate
what happened.
Further more DiagnosticSources exists for various purposes e.g (de)serialization times, time to first byte & various counters
TestableResponseFactory can be used to create response objects for use in unit tests.
Example code using the Moq library:
var response = TestableResponseFactory.CreateSuccessfulResponse<SearchResponse<Document>>(new(), 200);
var mock = new Mock<ElasticsearchClient>();
mock
.Setup(m => m.SearchAsync<Document>(It.IsAny<SearchRequest>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(response);