Skip to content

Add an HTTP client for service invocation and default to using it#182

Merged
artursouza merged 1 commit into
dapr:masterfrom
wcs1only:http_invocation
Jan 30, 2021
Merged

Add an HTTP client for service invocation and default to using it#182
artursouza merged 1 commit into
dapr:masterfrom
wcs1only:http_invocation

Conversation

@wcs1only

@wcs1only wcs1only commented Jan 28, 2021

Copy link
Copy Markdown
Contributor

Description

Created an HTTP client to use for service invocation. Also added a configuration option allow GRPC to be used as well.

Note: This PR was getting quite long, so I've split out another issue to add tracing.

Issue reference

We strive to have all PR being opened based on an issue, where the problem or feature have been discussed prior to implementation.

Please reference the issue this PR will close: #176

Checklist

Please make sure you've completed the relevant tasks for this PR, out of the following list:

  • Code compiles correctly
  • Created/updated tests
  • Extended the documentation

@wcs1only wcs1only force-pushed the http_invocation branch 11 times, most recently from 027d418 to a70aa3b Compare January 29, 2021 04:07
@codecov

codecov Bot commented Jan 29, 2021

Copy link
Copy Markdown

Codecov Report

Merging #182 (0ce0695) into master (803f286) will increase coverage by 1.54%.
The diff coverage is 89.23%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #182      +/-   ##
==========================================
+ Coverage   87.11%   88.65%   +1.54%     
==========================================
  Files          47       50       +3     
  Lines        1862     1948      +86     
==========================================
+ Hits         1622     1727     +105     
+ Misses        240      221      -19     
Impacted Files Coverage Δ
dapr/clients/http/dapr_actor_http_client.py 48.57% <37.50%> (+11.28%) ⬆️
dapr/clients/http/client.py 93.47% <93.47%> (ø)
dapr/clients/main.py 95.45% <95.45%> (ø)
dapr/clients/__init__.py 100.00% <100.00%> (ø)
dapr/clients/grpc/_response.py 94.28% <100.00%> (+0.12%) ⬆️
dapr/clients/grpc/client.py 91.21% <100.00%> (+1.35%) ⬆️
dapr/clients/http/dapr_invocation_http_client.py 100.00% <100.00%> (ø)
dapr/conf/global_settings.py 100.00% <100.00%> (ø)
dapr/serializers/json.py 89.47% <100.00%> (ø)
... and 4 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 803f286...0ce0695. Read the comment docs.

@wcs1only wcs1only force-pushed the http_invocation branch 3 times, most recently from 3714150 to ba83fb7 Compare January 29, 2021 23:54
@wcs1only wcs1only marked this pull request as ready for review January 30, 2021 00:00
Comment thread dapr/clients/__init__.py Outdated
from dapr.clients.base import DaprActorClientBase
from dapr.clients.exceptions import DaprInternalError, ERROR_CODE_UNKNOWN
from dapr.clients.grpc.client import DaprClient
from dapr.clients.generic import DaprClient

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generic is an overloaded term here. Can you name this package something else? Maybe main?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, can do.

Comment thread dapr/clients/generic.py
http_querystring: Optional[MetadataTuple] = None) -> InvokeMethodResponse:

if self.invocation_client:
return self.invocation_client.invoke_method(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why tests do not cover this if-else?

@wcs1only wcs1only Jan 30, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unit tests are hitting the DaprHttpInvocationClient class directly

Comment thread dapr/clients/grpc/_response.py Outdated
matched with the response data type
"""

if self.content_type == "application/x-protobuf":

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handle lower case vs upper case and content type optional suffix (application/x-protobuf; gzip)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The http library already correctly parses out the suffix for us, but I'll add a test to confirm this. Will also make case sensitive.



class DaprClient:
class DaprGrpcClient:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why renaming it if it is in another package?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because there is a new DaprClient which inherits from this class. Would be confusing if I named it the same, wouldn't it?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can name it differently when importing it. It is already in another package.

@wcs1only wcs1only Jan 30, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but we only named it so generically in the first place because we only had the gRPC client and nothing else. Now that we have both gRPC and HTTP, naming them more specifically makes sense.

Comment thread dapr/clients/http/client.py
Comment thread dapr/serializers/json.py
dict_obj = obj

# importing this from top scope creates a circular import
from dapr.actor.runtime.config import ActorRuntimeConfig

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait. Why we did not have this before?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We did, I just moved it out of the module scope.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean we had a circular import before?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, if I attempted include the json serializer without including all the actor classes first, it would try to pull in ActorRuntimeConfig which would pull in the rest of the actor classes, which would pull in the json serializer. This was the easiest way to break the loop.

Comment thread tests/clients/test_dapr_grpc_client.py Outdated
from unittest.mock import patch

from dapr.clients.grpc.client import DaprClient
from dapr.clients.grpc.client import DaprGrpcClient as DaprClient

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is odd because it was named correctly before.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what I mean, you can just name it DaprGrpcClient when using it. So the class can keep the original name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but I'd rather not have two classes which are both called DaprClient in the overall project, even if I can alias one of them away. Prefer to just call the DaprGrpcClient the same everywhere and use the generic name DaprClient only for the public facing class that does both Grpc and HTTP. I've updated this to not use an alias, rather just use the name DaprGrpcClient everywhere, so there is no ambiguity anywhere.

if http_verb is not None:
verb = http_verb

headers = {}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need DAPR_API_TOKEN and the traceparent header to be set here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ended up putting this in dapr/clients/http/client.py:50 so it can be shared with the Actor API client.

@wcs1only

Copy link
Copy Markdown
Contributor Author

Tracing and API token added. I've verified the sample. Everything looks right, though the grpc integration has an extra span in the stack.

@wcs1only wcs1only force-pushed the http_invocation branch 2 times, most recently from 3de731f to c159dd5 Compare January 30, 2021 05:00
@wcs1only wcs1only requested a review from artursouza January 30, 2021 05:02
@artursouza artursouza merged commit a115d9b into dapr:master Jan 30, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Makes service method API invocations over HTTP by default.

2 participants