Skip to content

Commit 9849f51

Browse files
use future to ensure first activate is as fast as possible. I am now thinking we just use a thread queue.
1 parent fe3fad8 commit 9849f51

File tree

1 file changed

+73
-8
lines changed

1 file changed

+73
-8
lines changed

core-api/src/main/java/com/optimizely/ab/event/internal/EventBuilder.java

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@
4141
import java.util.List;
4242
import java.util.Map;
4343
import java.util.UUID;
44+
import java.util.concurrent.Callable;
4445
import java.util.concurrent.ExecutorService;
4546
import java.util.concurrent.Executors;
47+
import java.util.concurrent.Future;
4648

4749
public class EventBuilder {
4850
private static final Logger logger = LoggerFactory.getLogger(EventBuilder.class);
@@ -55,6 +57,8 @@ public class EventBuilder {
5557
@VisibleForTesting
5658
public final EventBatch.ClientEngine clientEngine;
5759

60+
private Future<EventBatch> primedEvent = null;
61+
5862
public EventBuilder() {
5963
this(EventBatch.ClientEngine.JAVA_SDK, BuildVersionInfo.VERSION);
6064
}
@@ -64,18 +68,33 @@ public EventBuilder(EventBatch.ClientEngine clientEngine, String clientVersion)
6468
this.clientVersion = clientVersion;
6569
this.serializer = DefaultJsonSerializer.getInstance();
6670

67-
Runnable r = new Runnable() {
68-
public void run() {
69-
primeSerializer();
71+
Callable<EventBatch> callable = new Callable<EventBatch>() {
72+
@Override
73+
public EventBatch call() throws Exception {
74+
EventBatch eventBatch = null;
75+
try {
76+
eventBatch = primeSerializer();
77+
} catch (Exception e) {
78+
logger.error("Problem priming the JsonSerializer ", e);
79+
}
80+
finally {
81+
return eventBatch;
82+
}
7083
}
7184
};
7285

73-
ExecutorService executor = Executors.newCachedThreadPool();
74-
executor.submit(r);
86+
ExecutorService ex = Executors.newSingleThreadExecutor();
87+
primedEvent = ex.submit(callable);
88+
ex.shutdown();
7589

7690
}
7791

78-
private void primeSerializer() {
92+
/**
93+
* primeSerializer primes the JsonSerializer and Json annotations from the EventBatch object and it's contained
94+
* hierarchy. The introspection overhead is very high for the first time hit. This sets up all the serializer
95+
* caching, taking the burden off of the first time hit in sending an event.
96+
*/
97+
private EventBatch primeSerializer() {
7998
Decision decision = new Decision("", "",
8099
"", false);
81100
Event impressionEvent = new Event(System.currentTimeMillis(),UUID.randomUUID().toString(), "",
@@ -86,15 +105,61 @@ private void primeSerializer() {
86105
List<Visitor> visitors = Arrays.asList(visitor);
87106
EventBatch eventBatch = new EventBatch(clientEngine.getClientEngineValue(), clientVersion, "", visitors, true, "", "");
88107
String payload = this.serializer.serialize(eventBatch);
89-
LogEvent retVal = new LogEvent(LogEvent.RequestMethod.POST, EVENT_ENDPOINT, Collections.<String, String>emptyMap(), payload);
90-
logger.debug(String.format("Prime Serializer with event body %s", retVal.getBody()));
108+
logger.debug("JSON Serializer primed for payload {}", payload);
109+
110+
return eventBatch;
111+
}
112+
113+
private LogEvent usePrimedEvent(@Nonnull ProjectConfig projectConfig,
114+
@Nonnull Experiment activatedExperiment,
115+
@Nonnull Variation variation,
116+
@Nonnull String userId,
117+
@Nonnull Map<String, String> attributes) {
118+
try {
119+
EventBatch eventBatch = primedEvent.get();
120+
primedEvent = null;
121+
Decision decision = new Decision(activatedExperiment.getLayerId(), activatedExperiment.getId(),
122+
variation.getId(), false);
123+
124+
eventBatch.getVisitors().get(0).getSnapshots().get(0).setDecisions(Arrays.asList(decision));
125+
Event event = eventBatch.getVisitors().get(0).getSnapshots().get(0).getEvents().get(0);
126+
event.setEntityId(activatedExperiment.getLayerId());
127+
128+
Visitor visitor = eventBatch.getVisitors().get(0);
129+
visitor.setVisitorId(userId);
130+
visitor.setAttributes(buildAttributeList(projectConfig, attributes));
131+
132+
eventBatch.setClientName(clientEngine.getClientEngineValue());
133+
eventBatch.setClientVersion(clientVersion);
134+
135+
eventBatch.setAccountId(projectConfig.getAccountId());
136+
eventBatch.setAnonymizeIp(projectConfig.getAnonymizeIP());
137+
eventBatch.setProjectId(projectConfig.getProjectId());
138+
eventBatch.setRevision(projectConfig.getRevision());
139+
140+
String payload = this.serializer.serialize(eventBatch);
141+
return new LogEvent(LogEvent.RequestMethod.POST, EVENT_ENDPOINT, Collections.<String, String>emptyMap(), payload);
142+
143+
}
144+
catch (Exception e) {
145+
logger.error("Problem getting lock ", e);
146+
return null;
147+
}
91148
}
92149

93150
public LogEvent createImpressionEvent(@Nonnull ProjectConfig projectConfig,
94151
@Nonnull Experiment activatedExperiment,
95152
@Nonnull Variation variation,
96153
@Nonnull String userId,
97154
@Nonnull Map<String, String> attributes) {
155+
if (primedEvent != null) {
156+
logger.debug("had to wait for prime");
157+
LogEvent logEvent = usePrimedEvent(projectConfig, activatedExperiment, variation,
158+
userId, attributes);
159+
if (logEvent != null) {
160+
return logEvent;
161+
}
162+
}
98163

99164
Decision decision = new Decision(activatedExperiment.getLayerId(), activatedExperiment.getId(),
100165
variation.getId(), false);

0 commit comments

Comments
 (0)