Skip to content

Commit e62dc08

Browse files
authored
HTTPClient and EventScheduler (#53)
1 parent ca155b3 commit e62dc08

File tree

1 file changed

+83
-3
lines changed

1 file changed

+83
-3
lines changed

doc/maintainers.md

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ created.
164164
`class Tracer` is what users configure, and it is how `Span`s are extracted from
165165
trace context or created as a trace's root. See [tracer.h][9].
166166

167-
`Tracer` has two methods:
167+
`Tracer` has two member functions:
168168

169169
- `create_span(...)`
170170
- `extract_span(...)`
@@ -224,10 +224,81 @@ uses the HTTP client to send a POST request to the Datadog Agent's
224224
[/v0.4/traces][21] endpoint. It's all callback-based.
225225

226226
### HTTPClient
227-
TODO
227+
`class HTTPClient` is an interface for sending HTTP requests. It's defined in
228+
[http_client.h][15].
229+
230+
The only kind of HTTP request that the library needs to make, currently, is a
231+
POST to the Datadog Agent's traces endpoint. `HTTPClient` has one member
232+
function for each HTTP method needed — so, currently just the one:
233+
```c++
234+
virtual Expected<void> post(const URL& url, HeadersSetter set_headers,
235+
std::string body, ResponseHandler on_response,
236+
ErrorHandler on_error) = 0;
237+
```
238+
It's callback-based. `post` returns almost immediately. It invokes `set_headers`
239+
before returning, in order to get the HTTP request headers. The request `body`
240+
is moved elsewhere for later processing. One of `on_response` or `on_error` will
241+
eventually be called, depending on whether a response was received or if an
242+
error occurred before a response was received. If something goes wrong setting
243+
up the request, then `post` returns an error. If `post` returns an error, then
244+
neither of `on_response` nor `on_error` will be called.
245+
246+
`HTTPClient` also has another member function:
247+
```c++
248+
virtual void drain(std::chrono::steady_clock::time_point deadline) = 0;
249+
```
250+
`drain` waits for any in-flight requests to finish, blocking up until no later
251+
than `deadline`. It's used to ensure "clean shutdown." Without it, on average
252+
the last one second of traces would be lost on shutdown. Implementations of
253+
`HTTPClient` that don't have a dedicated thread need not support `drain`; in
254+
those cases, `drain` returns immediately.
255+
256+
The default implementation of `HTTPClient` is [class Curl : public
257+
HTTPClient][18], which uses libcurl's [multi interface][20] together with a
258+
dedicated thread as an event loop.
259+
260+
`class Curl` is also used within NGINX in Datadog's NGINX module,
261+
[nginx-datadog][22]. This is explicitly [discouraged][23] in NGINX's developer
262+
documentation, but libcurl-with-a-thread is widely used within NGINX modules
263+
regardless. One improvement that I am exploring is to use libcurl's
264+
"[multi_socket][24]" mode, which allows libcurl to utilize someone else's event
265+
loop, obviating the need for another thread. libcurl can then be made to use
266+
NGINX's event loop, as is done in [an example library][25].
267+
268+
For now, though, nginx-datadog uses the threaded `class Curl`.
269+
270+
[Envoy's Datadog tracing integration][26] uses a different implementation,
271+
[class AgentHTTPClient : public HTTPClient, ...][27], which uses Envoy's
272+
built-in HTTP facilities. libcurl is not involved at all.
228273

229274
### EventScheduler
230-
TODO
275+
As of this writing, `class DatadogAgent` flushes batches of finished trace
276+
segments to the Datadog Agent once every two second [by default][28].
277+
278+
It does this by scheduling a recurring event with an `EventScheduler`, which is
279+
an interface defined in [event_scheduler.h][16].
280+
281+
`EventScheduler` has one member function:
282+
```c++
283+
virtual Cancel schedule_recurring_event(
284+
std::chrono::steady_clock::duration interval,
285+
std::function<void()> callback) = 0;
286+
```
287+
Every `interval`, the scheduler will invoke `callback`, starting an initial
288+
`interval` after `schedule_recurring_event` is called. The caller can invoke the
289+
returned `Cancel` to prevent subsequent invocations of `callback`.
290+
291+
The default implementation of `EventScheduler` is [class ThreadedEventScheduler
292+
: public EventScheduler][19], which uses a dedicated thread for executing
293+
scheduled events at the correct time. It was a fun piece of code to write.
294+
295+
Datadog's NGINX module, [nginx-datadog][22] uses a different implementation,
296+
[class NgxEventScheduler : public EventScheduler][29], which uses NGINX's own
297+
event loop instead of a dedicated thread.
298+
299+
[Envoy's Datadog tracing integration][26] also uses a different implementation,
300+
[class EventScheduler : public EventScheduler][30], which uses Envoy's built-in
301+
event dispatch facilities.
231302
232303
### Configuration
233304
TODO
@@ -281,3 +352,12 @@ TODO
281352
[19]: ../src/datadog/threaded_event_scheduler.h
282353
[20]: https://curl.se/libcurl/c/libcurl-multi.html
283354
[21]: https://github.com/DataDog/datadog-agent/blob/9d57c10a9eeb3916e661d35dbd23c6e36395a99d/pkg/trace/api/version.go#L22
355+
[22]: https://github.com/DataDog/nginx-datadog
356+
[23]: https://nginx.org/en/docs/dev/development_guide.html#http_requests_to_ext
357+
[24]: https://curl.se/libcurl/c/curl_multi_socket_action.html
358+
[25]: https://github.com/dgoffredo/nginx-curl
359+
[26]: https://github.com/envoyproxy/envoy/tree/main/source/extensions/tracers/datadog#datadog-tracer
360+
[27]: https://github.com/envoyproxy/envoy/blob/main/source/extensions/tracers/datadog/agent_http_client.h
361+
[28]: https://github.com/DataDog/dd-trace-cpp/blob/ca155b3da65c2dc235cf64a28f8e0d8fdab3700c/src/datadog/datadog_agent_config.h#L50-L51
362+
[29]: https://github.com/DataDog/nginx-datadog/blob/master/src/ngx_event_scheduler.h
363+
[30]: https://github.com/envoyproxy/envoy/blob/main/source/extensions/tracers/datadog/event_scheduler.h

0 commit comments

Comments
 (0)