Зависимость:
<dependency>
io.keen</groupId>
keen-client-api-java</artifactId>
5.2.0</
</dependency>
Создание бина:
@Bean
public KeenClient keenClient() {
KeenClient keenClient = new JavaKeenClientBuilder().build();
keenClient.setDefaultProject(new KeenProject(projectId, writeKey, readKey));
keenClient.setDebugMode(debugMode);
if (enableLogging) {
KeenLogging.enableLogging();
}
return keenClient;
}
Определение услуги:
@Service
public class KeenAnalyticsService implements AnalyticsService {
private static final Logger LOG = LoggerFactory.getLogger(KeenAnalyticsService.class);
private final KeenClient keenClient;
public static final String ID = "id";
public static final String USER_LOGIN_EVENT = "user_login_event";
@Autowired
public KeenAnalyticsService(KeenClient keenClient) {
this.keenClient = keenClient;
}
@Override
public void submitUserLoginEvent(UserLoginAnalyticsEvent userLoginAnalyticsEvent) {
Map<String, Object> event = Maps.newHashMap();
event.put(USER_LOGIN_EVENT, userLoginAnalyticsEvent);
addEvent(USER_LOGIN_EVENT, event);
}
private void addEvent(String collection, Map<String, Object> event) {
addEvent(collection, event, Maps.newHashMap());
}
private void addEvent(String collection, Map<String, Object> event, Map<String, Object> keenProperties) {
if (!event.containsKey(ID)) {
String id = UUID.randomUUID().toString();
LOG.info("Adding {} Keen event with ID ({})", collection, id);
event.put(ID, id);
} else {
LOG.info("Adding {} Keen event with existing ID ({})", collection, event.get(ID));
}
try {
keenClient.addEventAsync(keenClient.getDefaultProject(), collection, event, keenProperties, new LoggingKeenCallback());
} catch (Throwable e) {
LOG.warn("Unable to add event", e);
}
}
private static class LoggingKeenCallback implements KeenDetailedCallback {
@Override
public void onSuccess() {}
@Override
public void onFailure(Exception e) {}
@Override
public void onSuccess(KeenProject project, String eventCollection, Map<String, Object> event, Map<String, Object> keenProperties) {
LOG.info("Successfully processed event asynchronously with ID({}) to Collection({})", event.get(ID), eventCollection);
}
@Override
public void onFailure(KeenProject project, String eventCollection, Map<String, Object> event, Map<String, Object> keenProperties, Exception e) {
LOG.warn("Unable to process event asynchronously with ID({}) to Collection({})", event.get(ID), eventCollection, e);
}
}
}
Я получаю следующую трассировку стека:
Exception in thread "pool-1-thread-1" java.lang.RuntimeException: java.net.SocketException: Operation not permitted (select/ poll failed)
at io.keen.client.java.KeenClient.handleFailure(KeenClient.java:1643)
at io.keen.client.java.KeenClient.addEvent(KeenClient.java:171)
at io.keen.client.java.KeenClient$1.run(KeenClient.java:243)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.net.SocketException: Operation not permitted (select/poll failed)
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
at sun.security.ssl.InputRecord.read(InputRecord.java:503)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:983)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1385)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1413)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1397)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:185)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLConnection.java:1316)
at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:1291)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:250)
at io.keen.client.java.http.UrlConnectionHttpHandler.sendRequest(UrlConnectionHttpHandler.java:86)
at io.keen.client.java.http.UrlConnectionHttpHandler.execute(UrlConnectionHttpHandler.java:30)
at io.keen.client.java.KeenClient.publishObject(KeenClient.java:1436)
at io.keen.client.java.KeenClient.publish(KeenClient.java:1370)
at io.keen.client.java.KeenClient.addEvent(KeenClient.java:168)
... 4 more
Есть какие-нибудь идеи относительно того, что может быть причиной проблемы? Эта проблема исчезает, когда я добавляю событие в синхронизации, а не в асинхронном режиме, но я бы предпочел добавить событие асинхронным, если это возможно.
Я на 99% уверен, что это лямбда, отсекающая выполнение до середины события, но я хотел быть уверен. Я лично не распознаю стековую трассировку, поэтому я могу только предположить, что из этого получилось.
Очевидно, что я не хочу откладывать попытки входа в систему пользователя больше, чем нужно, но если я запускаю острое событие асинхронно, как последнее, что я делаю, прежде чем возвращать результат входа в систему пользователю, то обязательно должен быть какой-то вид проблемы синхронизации, связанной с закрытием контейнера и острым отправляемым событием.
Опять же, лямбда может быть достаточно умна, чтобы дождаться окончания порожденных детьми потоков. С другой стороны, это не может быть. Может завершиться, когда основной поток завершит работу по проекту.
Интересно, может ли кто-нибудь из команды Keen или команды Lambda пролить на это больше света?