Skip to content

Commit 9e8b64f

Browse files
authored
Handling recycling race and volatile read-writes in Apache Async client (#662)
1 parent 0323be3 commit 9e8b64f

File tree

2 files changed

+13
-15
lines changed

2 files changed

+13
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* ClassCastException related to async instrumentation of Pilotfish Executor causing thread hang (applied workaround)
2020
* NullPointerException when computing Servlet transaction name with null HTTP method name
2121
* FileNotFoundException when trying to find implementation version of jar with encoded URL
22+
* NullPointerException when closing Apache AsyncHttpClient request producer
2223

2324
# 1.6.1
2425

apm-agent-plugins/apm-apache-httpclient-plugin/src/main/java/co/elastic/apm/agent/httpclient/HttpAsyncRequestProducerWrapper.java

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,21 @@
3636
import org.apache.http.nio.protocol.HttpAsyncRequestProducer;
3737
import org.apache.http.protocol.HttpContext;
3838

39-
import javax.annotation.Nullable;
4039
import java.io.IOException;
4140

4241
public class HttpAsyncRequestProducerWrapper implements HttpAsyncRequestProducer, Recyclable {
4342
private final ApacheHttpAsyncClientHelperImpl helper;
44-
private HttpAsyncRequestProducer delegate;
45-
private @Nullable HttpRequest request;
46-
private volatile Span span;
43+
private volatile HttpAsyncRequestProducer delegate;
44+
private Span span;
4745

4846
HttpAsyncRequestProducerWrapper(ApacheHttpAsyncClientHelperImpl helper) {
4947
this.helper = helper;
5048
}
5149

5250
public HttpAsyncRequestProducerWrapper with(HttpAsyncRequestProducer delegate, Span span) {
53-
// Order is important due to visibility - write to span last on this (initiating) thread
54-
this.delegate = delegate;
51+
// Order is important due to visibility - write to delegate last on this (initiating) thread
5552
this.span = span;
53+
this.delegate = delegate;
5654
return this;
5755
}
5856

@@ -63,27 +61,26 @@ public HttpHost getTarget() {
6361

6462
@Override
6563
public HttpRequest generateRequest() throws IOException, HttpException {
66-
// first read the volatile span
67-
final Span localSpan = this.span;
68-
request = delegate.generateRequest();
64+
// first read the volatile, span will become visible as a result
65+
HttpRequest request = delegate.generateRequest();
6966

7067
if (request != null) {
7168
RequestLine requestLine = request.getRequestLine();
7269
if (requestLine != null) {
7370
String method = requestLine.getMethod();
74-
localSpan.withName(method).appendToName(" ");
71+
span.withName(method).appendToName(" ");
7572
span.getContext().getHttp().withMethod(method).withUrl(requestLine.getUri());
7673
}
7774

78-
request.setHeader(TraceContext.TRACE_PARENT_HEADER, localSpan.getTraceContext().getOutgoingTraceParentHeader().toString());
75+
request.setHeader(TraceContext.TRACE_PARENT_HEADER, span.getTraceContext().getOutgoingTraceParentHeader().toString());
7976
}
8077

8178
HttpHost host = getTarget();
8279
//noinspection ConstantConditions
8380
if (host != null) {
8481
String hostname = host.getHostName();
8582
if (hostname != null) {
86-
localSpan.appendToName(hostname);
83+
span.appendToName(hostname);
8784
}
8885
}
8986

@@ -118,14 +115,14 @@ public void resetRequest() throws IOException {
118115

119116
@Override
120117
public void close() throws IOException {
121-
helper.recycle(this);
122118
delegate.close();
119+
helper.recycle(this);
123120
}
124121

125122
@Override
126123
public void resetState() {
127-
request = null;
128-
delegate = null;
124+
// Order is important due to visibility - write to delegate last
129125
span = null;
126+
delegate = null;
130127
}
131128
}

0 commit comments

Comments
 (0)