Open apotterri opened 8 months ago
@apotterri Is this for the JetBrains plugin or for https://github.com/getappmap/appmap-java?
Oops, sorry.
FWIW, I think it is the best we can do with the current AppMap spec while maintaining coherent UX, even if the data thus generated isn't technically 100% accurate (esp. re. event ordering and thread IDs).
I investigated the current agent a little more, to see how it handles code that uses an ExecutorService
. (This is my original example, updated so it compiles, and allows comparison of implementations.)
@DeleteMapping("dolphins")
public String dolphins() throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
if (true) {
Future<Object> future1 = executorService.submit((Callable<Object>) () -> {
DolphinChat dc1 = new DolphinChat();
return dc1.say("So") + dc1.say("long,");
});
Future<Object> future2 = executorService.submit((Callable<Object>) () -> {
DolphinChat dc2 = new DolphinChat();
return dc2.say("and thanks for") + dc2.say("all the fish");
});
System.out.println(future1.get() + " " + (String) future2.get());
} else {
Supplier<String> future1 = () -> {
DolphinChat dc1 = new DolphinChat();
return dc1.say("So") + dc1.say("long,");
};
Supplier<String> future2 = () -> {
DolphinChat dc2 = new DolphinChat();
return dc2.say("and thanks for") + dc2.say("all the fish");
};
System.out.println(future1.get() + " " + (String) future2.get());
}
NextUp nu = new NextUp();
nu.say("Mostly Harmless");
return "deleted";
}
When run with process or remote recording, this code produces this sequence diagram:
Changing
if (true) {
to
if (false) {
i.e. running without an ExecutorService
, you get this sequence diagram:
However, in both cases, events for the calls to DolphinChat
and DolphinChatImpl
methods appear in the AppMaps. When running with the ExecutorService
, however, the thread_id
in those events different from the thread_id
for the http_server_request
(of course), so they don't show up in the sequence diagrams.
Do you have Limit Root events to HTTP checked?
- task recording stops when the method that called
ExecutorService.submit
returns. [What should happen if there are outstandingFuture
s?]
In appmap-node, a similar case (outstanding promises when recording ends) would show up in an AppMap as a Promise with value: "Promise { pending }"
, which is detected by the unfulfilled promises scanner and usually indicates a bug. Perhaps something similar could be done here to enable similar detection.
Currently, if an HTTP endpoint (e.g. a Spring Controller) uses an
ExecutorService
to run a task, none of that processing shows up in the AppMap. For example:the calls to
DolphinChat
methods won't show up in the AppMap.Instead, the (pseudo) events should look like this:
This says they all have the same thread id (that matches the thread that creates the
ExecutorService
). The ordering of thecall
andreturn
events show that the calls toDolphinChat.say
happened in aRunnable
/Callable
submitted to anExecutorService
. Note that the order of the completeRunnable.run
call chains may not match the order in the code, of course, because they were run on separate threads.Test cases:
dolphins
, generates an AppMapExecutorService.submit
has been calledCallable
andRunnable
passed toExecutorService.submit
are handled correctlydolphins
generates an AppMapdolphins
endpoint generates an AppMapFuture.cancel
is called. [What should happen to the task's recording?]ExecutorService.submit
returns. [What should happen if there are outstandingFuture
s?]