It seems that the threads from the ExecutorService from the BatchEmitter class are preventing the exit (I am not a Java expert). My workaround is to change the close() method (as in the Android tracker).

Thanks for the comment. No, it never closes. The issue is that the threads don’t die when the end of main() is reached. They only die when killed manually or by System.exit().

There is an issue with my proposed fix; because flushBuffer() call does not block, it’s possible that the subsequent call to executor.shutdown() is made before the events are sent.

When I created an app sending lots of events this caused some events not to be sent and the HttpClientAdapter to raise plenty of exceptions (we closed the HttpClientAdapter as soon as the call to close() returned).

Anyway, i think the easiest solution is to have a time-out on the shutdown (alternatively, we could keep track of all events buffered and wait until they are all sent).

I was affected by this problem as well. In my code, I used explicit System.exit() and as the result no snowplow events were ever sent out. To combat the issue, I established an java.util.concurrent.atomic.AtomicInteger singleton counter. The counter is incremented every time an event is tracked and decremented by the number of success + fail event counters in via emitter callback. Prior to exit I sleep in 300 ms. increments, flushing emitter buffer and waiting for the atomic counter to get to 0.

A. This solution is not taking into account any retry / backoff strategy that may be in play.
B. It also seems that if the event generating thread is busy the event emitter threads never get to execute (even when I Thread.yield() ). So the bulk of the submitted events is sitting waiting to be emitted at the end of the program execution.
C. I think a better solution would use a shutdown hook [ Runtime.getRuntime().addShutdownHook(Thread) ] to hide the particulars under the hood, just like deletion of temporary files on jvm exit is handled in the File module.
A more comprehensive resolution would be a huge welcome. Unfortunately I’m not that good at concurrency to offer a PR.