Client#
Client
enables you to send Documents to a running Flow
. Same as Gateway, Client supports four networking protocols: gRPC, HTTP, WebSocket and GraphQL with/without TLS.
You may have observed two styles of using a Client in the docs:
from jina import Flow
f = Flow()
with f:
f.post('/')
from jina import Client
c = Client(...) # must match the Flow setup
c.post('/')
The implicit style is easier in debugging and local development, as you don’t need to specify the host, port and protocol of the Flow. However, it makes very strong assumptions on (1) one Flow only corresponds to one client (2) the Flow is running on the same machine as the Client. For those reasons, explicit style is recommended for production use.
Hint
If you want to connect to your Flow from a programming language other than Python, please follow the third party client documentation.
Connect#
To connect to a Flow started by:
from jina import Flow
with Flow(port=1234, protocol='grpc') as f:
f.block()
────────────────────────── 🎉 Flow is ready to serve! ──────────────────────────
╭────────────── 🔗 Endpoint ───────────────╮
│ ⛓ Protocol GRPC │
│ 🏠 Local 0.0.0.0:1234 │
│ 🔒 Private 192.168.1.126:1234 │
│ 🌍 Public 87.191.159.105:1234 │
╰──────────────────────────────────────────╯
The Client has to specify the followings parameters to match the Flow and how it was set up:
the
protocol
it needs to use to communicate with the Flowthe
host
and theport
as exposed by the Flowif it needs to use
TLS
encryption (to connect to aFlow
that has been configured to use TLS in combination with gRPC, http, or websocket)
Hint
Default port
The default port for the Client is 80
unless you are using TLS
encryption it will be 443
You can define these parameters by passing a valid URI scheme as part of the host
argument:
from jina import Client
Client(host='http://my.awesome.flow:1234')
Client(host='ws://my.awesome.flow:1234')
Client(host='grpc://my.awesome.flow:1234')
from jina import Client
Client(host='https://my.awesome.flow:1234')
Client(host='wss://my.awesome.flow:1234')
Client(host='grpcs://my.awesome.flow:1234')
Equivalently, you can pass each relevant parameter as a keyword argument:
from jina import Client
Client(host='my.awesome.flow', port=1234, protocol='http')
Client(host='my.awesome.flow', port=1234, protocol='websocket')
Client(host='my.awesome.flow', port=1234, protocol='grpc')
from jina import Client
Client(host='my.awesome.flow', port=1234, protocol='http', tls=True)
Client(host='my.awesome.flow', port=1234, protocol='websocket', tls=True)
Client(host='my.awesome.flow', port=1234, protocol='grpc', tls=True)
You can also use a mix of both:
from jina import Client
Client(host='https://my.awesome.flow', port=1234)
Client(host='my.awesome.flow:1234', protocol='http', tls=True)
Caution
You can’t define these parameters both by keyword argument and by host scheme - you can’t have two sources of truth. Example: the following code will raise an exception:
from jina import Client
Client(host='https://my.awesome.flow:1234', port=4321)
Caution
We apply RLock
to avoid this gRPC issue, so that grpc
clients can be used in a multi-threaded environment.
What you should do, is to rely on asynchronous programming or multi-processing rather than multi-threading.
For instance, if you’re building a web server, you can introduce multi-processing based parallelism to your app using
gunicorn
: gunicorn main:app --workers 4 --worker-class uvicorn.workers.UvicornWorker ...
Client API#
When using docarray>=0,30
, you specify the schema that you expect the Deployment or Flow to return. You can pass the return type by using the return_type
parameter in the client.post
method:
from jina import Client
from docarray import DocList, BaseDoc
class InputDoc(BaseDoc):
text: str = ''
class OutputDoc(BaseDoc):
tags: Dict[str, int] = {}
c = Client(host='https://my.awesome.flow:1234', port=4321)
c.post(
on='/',
inputs=InputDoc(),
return_type=DocList[OutputDoc],
)
Enable compression#
If the communication to the Gateway is via gRPC, you can pass compression
parameter to post()
to benefit from gRPC compression methods.
The supported choices are: None, gzip
and deflate
.
from jina import Client
client = Client()
client.post(..., compression='Gzip')
Note that this setting is only effective the communication between the client and the Flow’s gateway.
One can also specify the compression of the internal communication as described here.
Test readiness of the server#
You can check the readiness from the client:
from jina import Deployment
dep = Deployment(port=12345)
with dep:
dep.block()
from jina import Client
client = Client(port=12345)
print(client.is_deployment_ready())
True
from jina import Flow
f = Flow(port=12345).add()
with f:
f.block()
from jina import Client
client = Client(port=12345)
print(client.is_flow_ready())
True
Simple profiling of the latency#
Before sending any real data, you can test the connectivity and network latency by calling the profiling()
method:
from jina import Client
c = Client(host='grpc://my.awesome.flow:1234')
c.profiling()
Roundtrip 24ms 100%
├── Client-server network 17ms 71%
└── Server 7ms 29%
├── Gateway-executors network 0ms 0%
├── executor0 5ms 71%
└── executor1 2ms 29%
Logging configuration#
Similar to the Flow logging configuration, the jina.Client
also accepts the log_config
argument. The Client can be configured as below:
from jina import Client
client = Client(log_config='./logging.json.yml')
If the Flow is configured with custom logging, the argument will be forwarded to the implicit client.
from jina import Flow
f = Flow(log_config='./logging.json.yml')
with f:
# the implicit client automatically uses the log_config from the Flow for consistency
f.post('/')