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 Flow

  • the host and the port as exposed by the Flow

  • if it needs to use TLS encryption (to connect to a Flow 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 ...

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 Flow#

Client offers an API to query these readiness endpoints. You can call is_flow_ready() or is_flow_ready(). It returns True if the Flow is ready, and False if it is not.

from jina import Flow

with Flow().add() as f:
    print(f.is_flow_ready())

print(f.is_flow_ready())
True
False
from jina import Flow

with Flow(port=12345).add() as f:
    f.block()
from jina import Client

client = Client(port=12345)
print(client.is_flow_ready())
True
from jina import Flow

with Flow(port=12345).add() as f:
    f.block()
jina ping flow grpc://localhost:12345
INFO   [email protected] ping grpc://localhost:12345 at 0 round...                                                                                              [09/08/22 12:58:13]
INFO   [email protected] ping grpc://localhost:12345 at 0 round takes 0 seconds (0.04s)
INFO   [email protected] ping grpc://localhost:12345 at 1 round...                                                                                              [09/08/22 12:58:14]
INFO   [email protected] ping grpc://localhost:12345 at 1 round takes 0 seconds (0.01s)
INFO   [email protected] ping grpc://localhost:12345 at 2 round...                                                                                              [09/08/22 12:58:15]
INFO   [email protected] ping grpc://localhost:12345 at 2 round takes 0 seconds (0.01s)
INFO   [email protected] avg. latency: 24 ms                                                                                                                    [09/08/22 12:58:16]
INFO   [email protected] ping grpc://localhost:12345 at 0 round...                                                                                              [09/08/22 12:59:00]
ERROR  [email protected] Error while getting response from grpc server <AioRpcError of RPC that terminated with:                                          [09/08/22 12:59:00]
               status = StatusCode.UNAVAILABLE
               details = "failed to connect to all addresses; last error: UNKNOWN: Failed to connect to remote host: Connection refused"
               debug_error_string = "UNKNOWN:Failed to pick subchannel {created_time:"2022-09-08T12:59:00.518707+02:00", children:[UNKNOWN:failed to
       connect to all addresses; last error: UNKNOWN: Failed to connect to remote host: Connection refused {grpc_status:14,
       created_time:"2022-09-08T12:59:00.518706+02:00"}]}"
       >
WARNI… [email protected] not responding, retry (1/3) in 1s
INFO   [email protected] ping grpc://localhost:12345 at 0 round takes 0 seconds (0.01s)
INFO   [email protected] ping grpc://localhost:12345 at 1 round...                                                                                              [09/08/22 12:59:01]
ERROR  [email protected] Error while getting response from grpc server <AioRpcError of RPC that terminated with:                                          [09/08/22 12:59:01]
               status = StatusCode.UNAVAILABLE
               details = "failed to connect to all addresses; last error: UNKNOWN: Failed to connect to remote host: Connection refused"
               debug_error_string = "UNKNOWN:Failed to pick subchannel {created_time:"2022-09-08T12:59:01.537293+02:00", children:[UNKNOWN:failed to
       connect to all addresses; last error: UNKNOWN: Failed to connect to remote host: Connection refused {grpc_status:14,
       created_time:"2022-09-08T12:59:01.537291+02:00"}]}"
       >
WARNI… [email protected] not responding, retry (2/3) in 1s
INFO   [email protected] ping grpc://localhost:12345 at 1 round takes 0 seconds (0.01s)
INFO   [email protected] ping grpc://localhost:12345 at 2 round...                                                                                              [09/08/22 12:59:02]
ERROR  [email protected] Error while getting response from grpc server <AioRpcError of RPC that terminated with:                                          [09/08/22 12:59:02]
               status = StatusCode.UNAVAILABLE
               details = "failed to connect to all addresses; last error: UNKNOWN: Failed to connect to remote host: Connection refused"
               debug_error_string = "UNKNOWN:Failed to pick subchannel {created_time:"2022-09-08T12:59:02.557195+02:00", children:[UNKNOWN:failed to
       connect to all addresses; last error: UNKNOWN: Failed to connect to remote host: Connection refused {grpc_status:14,
       created_time:"2022-09-08T12:59:02.557193+02:00"}]}"
       >
WARNI… [email protected] not responding, retry (3/3) in 1s
INFO   [email protected] ping grpc://localhost:12345 at 2 round takes 0 seconds (0.02s)
WARNI… [email protected] message lost 100% (3/3)

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%