Skip to content

Commit

Permalink
Merge pull request #58 from joechild-pace/lazy-init
Browse files Browse the repository at this point in the history
Add "lazy" connection option
  • Loading branch information
timbu authored Oct 3, 2023
2 parents ce2dca9 + 50c3bff commit 9d6f985
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 6 deletions.
6 changes: 4 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ repos:
- id: check-merge-conflict
- id: fix-encoding-pragma
- id: flake8
- repo: https://github.com/mattbennett/mirrors-isort.git
rev: master
- repo: https://github.com/PyCQA/isort
rev: 4.3.21
hooks:
- id: isort
- repo: https://github.com/ambv/black
rev: 22.10.0
hooks:
- id: black
# TODO remove this when black is updated
additional_dependencies: [ 'click==8.0.4' ]
25 changes: 22 additions & 3 deletions nameko_grpc/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,16 @@ def __init__(
compression_algorithm="none",
compression_level="high",
ssl=False,
lazy_startup=False,
):
self.target = target
self.stub = stub
self.compression_algorithm = compression_algorithm
self.compression_level = compression_level # NOTE not used
self.ssl = SslConfig(ssl)
self.lazy_startup = lazy_startup
self._channel_creation_lock = threading.Lock()
self._channel = None

def spawn_thread(self, target, args=(), kwargs=None, name=None):
raise NotImplementedError
Expand All @@ -144,11 +148,26 @@ def default_compression(self):
return "identity"

def start(self):
self.channel = ClientChannel(self.target, self.ssl, self.spawn_thread)
self.channel.start()
if not self.lazy_startup:
self._start_channel()

def _start_channel(self):
with self._channel_creation_lock:
if self._channel is None:
channel = ClientChannel(self.target, self.ssl, self.spawn_thread)
channel.start()
self._channel = channel

def stop(self):
self.channel.stop()
if self._channel is not None:
self._channel.stop()
self._channel = None

@property
def channel(self):
if self._channel is None:
self._start_channel()
return self._channel

def timeout(self, send_stream, response_stream, deadline):
start = time.time()
Expand Down
5 changes: 4 additions & 1 deletion test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -352,18 +352,21 @@ def make(
proto_name=None,
compression_algorithm="none",
compression_level="high",
lazy_startup=False,
service_url="//localhost:{}".format(grpc_port),
):
if proto_name is None:
proto_name = service_name

stubs = load_stubs(proto_name)
stub_cls = getattr(stubs, "{}Stub".format(service_name))
client = Client(
"//localhost:{}".format(grpc_port),
service_url,
stub_cls,
compression_algorithm,
compression_level,
ssl_options,
lazy_startup=lazy_startup,
)
clients.append(client)
return client.start()
Expand Down
27 changes: 27 additions & 0 deletions test/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,30 @@ def generate_requests():
("A", 1),
("B", 2),
]


class TestLazy:
def test_lazy_client(self, start_nameko_client, server, protobufs):
client = start_nameko_client("example", lazy_startup=True)
response = client.unary_unary(protobufs.ExampleRequest(value="A"))
assert response.message == "A"

# Note lack of server fixture
def test_lazy_client_does_not_connect_on_start(
self, start_nameko_client, protobufs, start_grpc_server
):
client = start_nameko_client("example", lazy_startup=True)

with pytest.raises(ConnectionRefusedError):
client.unary_unary(protobufs.ExampleRequest(value="A"))

start_grpc_server("example")

# After starting the server, should now work
response = client.unary_unary(protobufs.ExampleRequest(value="A"))
assert response.message == "A"

# Note lack of server fixture
def test_nonlazy_client_connects_on_start(self, start_nameko_client, protobufs):
with pytest.raises(ConnectionRefusedError):
start_nameko_client("example", lazy_startup=False)

0 comments on commit 9d6f985

Please sign in to comment.