Skip to content

Sending sync request through http_client#448

Merged
lalitb merged 26 commits intoopen-telemetry:mainfrom
lalitb:sync-http-request
Jan 26, 2021
Merged

Sending sync request through http_client#448
lalitb merged 26 commits intoopen-telemetry:mainfrom
lalitb:sync-http-request

Conversation

@lalitb
Copy link
Copy Markdown
Member

@lalitb lalitb commented Dec 14, 2020

Currently, http_client api supports sending async http requests, with error and response received through callback. For exporters, we need to have the status of http request returned from export function ( refer - #444 (comment) ) . Adding a method to send sync request in client interface, along with it's curl implementation.

Summary of changes:
2. Split SessionManager to HttpClient ( default async http client ) and HttpClientSync ( sync http client )
2. Sync Request Example:

GET:

  HttpClientSync httpClient;
  auto result = httpClient.Get(url);
  if (result){
    auto response = result.GetResponse();
  } else {
    std::cout << result.GetSessionState();
  }

POST:

  HttpClientSync httpClient;
  auto result = httpClient.Post(url, data, headers); // GET request
  if (result){
    auto response = result.GetResponse();
  } else {
    std::cout << result.GetSessionState();
  }

Pending Change:

  1. Add test case for HTTP POST sync request.

@lalitb lalitb requested a review from a team December 14, 2020 15:29
@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 14, 2020

Codecov Report

Merging #448 (d43d5ae) into main (8fd86ed) will decrease coverage by 0.29%.
The diff coverage is 78.88%.

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #448      +/-   ##
==========================================
- Coverage   94.46%   94.16%   -0.30%     
==========================================
  Files         194      195       +1     
  Lines        8509     8571      +62     
==========================================
+ Hits         8038     8071      +33     
- Misses        471      500      +29     
Impacted Files Coverage Δ
...t/src/http/client/curl/http_client_factory_curl.cc 60.00% <33.33%> (-40.00%) ⬇️
ext/src/http/client/curl/http_client_curl.cc 55.55% <55.55%> (ø)
...ntelemetry/ext/http/client/curl/http_client_curl.h 82.07% <65.78%> (-13.05%) ⬇️
...lemetry/ext/http/client/curl/http_operation_curl.h 78.52% <100.00%> (-3.91%) ⬇️
...nclude/opentelemetry/ext/http/client/http_client.h 95.45% <100.00%> (+4.54%) ⬆️
ext/test/http/curl_http_test.cc 94.50% <100.00%> (+0.49%) ⬆️
sdk/test/metrics/counter_aggregator_test.cc 98.21% <0.00%> (-1.79%) ⬇️
sdk/src/logs/batch_log_processor.cc 93.82% <0.00%> (-1.24%) ⬇️
... and 1 more

Comment thread ext/test/http/curl_http_test.cc
@lalitb
Copy link
Copy Markdown
Member Author

lalitb commented Dec 18, 2020

@maxgolov Need you review for this : ) Thanks.

Comment thread ext/test/http/curl_http_test.cc Outdated
received_requests_.clear();
curl::SessionManager session_manager;

auto session =
Copy link
Copy Markdown
Contributor

@maxgolov maxgolov Dec 18, 2020

Choose a reason for hiding this comment

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

If I need to send 2 synchronous requests from two different threads, do I need to create two separate sessions?

Why do I have to specify session IP, port, and Uri separately - is there a reason to not having something like:

oReq.open("GET", "http://www.example.org/example.txt")

Copy link
Copy Markdown
Member Author

@lalitb lalitb Jan 13, 2021

Choose a reason for hiding this comment

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

If I need to send 2 synchronous requests from two different threads, do I need to create two separate sessions?

Session is a logical entity here for maintaining session id, ssl cert ( if needed ), callback object ( for async request) etc. HTTP is stateless protocol, so it doesn't makes sense to have ongoing session, and sending HTTP Requests over that.

Why do I have to specify session IP, port, and Uri separately - is there a reason to not having something like:
oReq.open("GET", "http://www.example.org/example.txt")

Yeah, its doable as separate PR.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ok, I have done the modified sync requests as below:

  HttpClient httpClient;
  auto result = httpClient.Get(url);
  if (result){
    auto response = result.GetResponse();
  } else {
    std::cout << result.GetSessionState();
  }

auto session = sessionManager.createSession("localhost", 8000);
auto request = session->CreateRequest();
request->AddHeader(..);
SessionState session_state;
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.

So this is not a session state - this is given request state?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Correct.

});
}

virtual std::unique_ptr<http_client::Response> SendRequestSync(
Copy link
Copy Markdown
Contributor

@maxgolov maxgolov Dec 18, 2020

Choose a reason for hiding this comment

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

I believe it would be much cleaner if you operate only on Response object rather than on SessionState. Let me elaborate - right now you have two possible states:

  • success - in this case you return Response and status code; or
  • failure - in this case you force the user to test if Response ptr is nullptr, and then inspect the SessionState parameter passed by reference.. which is not really Session state (because Session may have multiple requests), but rather this exact Request state.

So since in reality it is Request state, can you have this aggregated on Response object - making sure that you always return Response: failed or succeeded, always return it. It may be successful response or empty response, failed response, with an indication on Response object that it's a failed response. Then you avoid the nullptr entirely, you avoid checking on two separate objects, and you can just propagate the object elsewhere to the place that needs to make a decision what to do next with that failed request-response pair.

Could you please clarify - if the original intent of SessionManager was to support more than one concurrent request at a time? If so, then SessionState is a misleading name for a synchronous request resultt. Session may have more than one request, one failed, one successful, and SessionState name does not represent the actual SessionManager Session state.

Copy link
Copy Markdown
Member Author

@lalitb lalitb Jan 13, 2021

Choose a reason for hiding this comment

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

Response object represents http-response containing - body, header and code. Any error during http handshake are returned in SessionState. This is to keep it consistent with how we achieve it in async requests:

EventHandler::OnResponse(Response &);
EventHandler::OnError(SessionState);
Session::SendRequest(EventHandler &); // async
unique_ptr<Request> Session::SendRequestSync(SessionState &); // sync

If it's fine, we can always return empty response in case of error, and the Response::status_code would be 0 in that case.

Session is more of logical entity, and doesn't represent multiple ongoing http requests.
SessionManager -> Multiple Sessions.
Single Session -> Single Request

{
// we have a http response
auto response = std::unique_ptr<Response>(new Response());
response->headers_ = curl_operation_->GetResponseHeaders();
Copy link
Copy Markdown
Contributor

@maxgolov maxgolov Dec 18, 2020

Choose a reason for hiding this comment

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

How do you propagate Response code? If you are using int for that, then in Java it'd typically allocate -1 for failed response status code, which can then be used to determine if request was actually processed, as in connected and got some response code from server.

Copy link
Copy Markdown
Member Author

@lalitb lalitb Jan 13, 2021

Choose a reason for hiding this comment

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

Currently we use uint16_t for status_code. If it's fine, we can always return empty response in case of error, and the Response::status_code would be 0 in that case ?

{
is_session_active_ = true;
std::string url = host_ + std::string(http_request_->uri_);
curl_operation_.reset(new HttpOperation(http_request_->method_, url, nullptr, RequestMode::Sync,
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.

Could we set RequestMode::Sync in SendSync() or just deduce it from SendSync() and SendAsync(). Is the inconsistency between ctor and SendSync() handled?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We do need to know the actual sync mode in ctor. There are some initializations done in ctor, and the sync mode information is used to propagate the error/results to clients.

Is the inconsistency between ctor and SendSync() handled?

What kind of inconsistency we are talking about.


// Object that stores the HTTP sessions that have been created
std::unique_ptr<ext::http::client::SessionManager> session_manager_;
std::unique_ptr<ext::http::client::HttpClient> session_manager_;
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.

Rename the variable name to http_client_ too?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

yeah, this needs to be done in both cc and h. I was thinking to change it once @maxgolov is fine with the current changes ( to avoid reverting back). But thanks for noticing it. I will add this as pending change in PR description.

std::unique_ptr<HttpOperation> curl_operation_;
uint64_t session_id_;
SessionManager &session_manager_;
HttpClient &session_manager_;
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.

Rename the variable to http_client_ as well?

Comment thread ext/include/opentelemetry/ext/http/client/curl/http_client_curl.h
Copy link
Copy Markdown
Contributor

@ThomsonTan ThomsonTan left a comment

Choose a reason for hiding this comment

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

LGTM with some minor comments.

Base automatically changed from master to main January 26, 2021 00:46
@lalitb lalitb merged commit 7c6220a into open-telemetry:main Jan 26, 2021
GerHobbelt pushed a commit to GerHobbelt/opentelemetry-cpp that referenced this pull request Mar 6, 2026
…and-patch-dependencies

Update github/codeql-action action to v3.29.9
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.

3 participants