How JavaConcurrent work in multithreading

Kibana version :

7.10.2

Elasticsearch version :

7.10.2

APM Server version :

1.21.0

APM Agent language and version :
Java
Browser version :
Chrome 79.0.3945.117
Original install method (e.g. download page, yum, deb, from source, etc.) and version :
download page and local setup
Fresh install or upgraded from other version?
No

**

Hello,
This question is related with other topic.

I would like to add "APM context" in custom multithread solution.
I check how that was done in "apm-java-concurrent-plugin" plugin. There is a class JavaConcurrent that add context to Callable or Runnable.

In this plugin there is a instrumentation class for executor co.elastic.apm.agent.concurrent.ExecutorInstrumentation


    public static class ExecutorRunnableInstrumentation extends ExecutorInstrumentation {

        @Nullable
        @AssignTo.Argument(0)
        @Advice.OnMethodEnter(suppress = Throwable.class, inline = false)
        public static Runnable onExecute(@Advice.This Executor thiz,
                                         @Advice.Argument(0) @Nullable Runnable runnable) {
            if (ExecutorInstrumentation.isExcluded(thiz)) {
                return runnable;
            }
            return JavaConcurrent.withContext(runnable, tracer);
        }

        @Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class, inline = false)
        public static void onExit(@Nullable @Advice.Thrown Throwable thrown,
                                   @Advice.Argument(value = 0) @Nullable Runnable runnable) {
            JavaConcurrent.doFinally(thrown, runnable);
        }     
    }

Code in onExecute JavaConcurrent.withContext(runnable, tracer) put object into WeakConcurrentMap

In onExit method this class call JavaConcurrent.doFinally(thrown, runnable); In this method object added by withContext metod is removed only when Throwable object is not null. Question is what about calls without error ? When such objects will be removed?

    public static void doFinally(@Nullable Throwable thrown, @Nullable Object contextObject) {
        needsContext.set(Boolean.TRUE);
        if (thrown != null && contextObject != null) {
            removeContext(contextObject);
        }
    }

I use JavaConcurrent in my plugin, but from debug I see that WeakConcurrentMap is not cleaning and even when thread stop working, object stay in collection.

Thank you for help.

Please see where this JavaConcurrent usage is done - the submission of a Runnable or Callable before execution. This removal of the context through doFinally is only for handling cases where the submission itself fails, not the actual execution. When submission succeeds, the context will be removed at the end of the run()/call() execution. If you apply this instrumentation to somewhere else in your code, right after the Runnable/Callable is created and still on the creating thread, and before the forked thread starts executing it, it should work.

However, since this is an internal API, its stability is not guaranteed.
Instead, consider using an external plugin. You would need to use your own implementation of JavaConcurrent, by using only SDK and public APIs, which are much more stable. I believe you should get what you need for that:

  • co.elastic.apm.agent.sdk.DynamicTransformer#ensureInstrumented()
  • co.elastic.apm.agent.sdk.weakmap.WeakMapSupplier
  • public API for starting/activating spans

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.